Generar tokens

En esta guía, se explica cómo generar un token, y los campos obligatorios y opcionales campos para tokens.

Para crear un token, redacta una cadena para firmar, a la que nos referimos como firma de salida en esta guía. El valor firmado incluye parámetros que describen el contenido que proteges, la fecha de vencimiento del valor firmado, etcétera.

Usas el valor firmado mientras creas una cadena de token. Para crear una cadena de token, debes componer los parámetros del token, como un código de autenticación de mensajes basado en hash (HMAC) de clave simétrica del valor firmado.

Media CDN usa el token compuesto final para ayudar a proteger tu contenido.

Crear un token

  1. Crea un valor firmado mediante la concatenación de una cadena que contenga el campos de token obligatorios y el token opcional deseado campos de entrenamiento. Separa cada campo y cualquier parámetro con un carácter de virgulilla ~.

  2. Firma el valor firmado con una firma Ed25519 o una clave simétrica HMAC

  3. Para crear el token, concatena una cadena que contenga los campos de token obligatorios y opcionales. Separa cada campo y cualquier parámetro con un carácter virgulilla ~.

    Cuando se compone el token, los valores de cada uno de los parámetros son los mismos entre el valor firmado y la cadena de token, con las siguientes excepciones:

    • FullPath
    • Headers

En la siguiente muestra de código, se indica cómo crear un token de manera programática:

Python

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

import base64
import datetime
import hashlib
import hmac

import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519


def base64_encoder(value: bytes) -> str:
    """
    Returns a base64-encoded string compatible with Media CDN.

    Media CDN uses URL-safe base64 encoding and strips off the padding at the
    end.
    """
    encoded_bytes = base64.urlsafe_b64encode(value)
    encoded_str = encoded_bytes.decode("utf-8")
    return encoded_str.rstrip("=")


def sign_token(
    base64_key: bytes,
    signature_algorithm: str,
    start_time: datetime.datetime = None,
    expiration_time: datetime.datetime = None,
    url_prefix: str = None,
    full_path: str = None,
    path_globs: str = None,
    session_id: str = None,
    data: str = None,
    headers: str = None,
    ip_ranges: str = None,
) -> str:
    """Gets the Signed URL Suffix string for the Media CDN' Short token URL requests.
    One of (`url_prefix`, `full_path`, `path_globs`) must be included in each input.
    Args:
        base64_key: Secret key as a base64 encoded string.
        signature_algorithm: Algorithm can be either `SHA1` or `SHA256` or `Ed25519`.
        start_time: Start time as a UTC datetime object.
        expiration_time: Expiration time as a UTC datetime object. If None, an expiration time 1 hour from now will be used.
        url_prefix: the URL prefix to sign, including protocol.
                    For example: http://example.com/path/ for URLs under /path or http://example.com/path?param=1
        full_path:  A full path to sign, starting with the first '/'.
                    For example: /path/to/content.mp4
        path_globs: a set of ','- or '!'-delimited path glob strings.
                    For example: /tv/*!/film/* to sign paths starting with /tv/ or /film/ in any URL.
        session_id: a unique identifier for the session
        data: data payload to include in the token
        headers: header name and value to include in the signed token in name=value format.  May be specified more than once.
                    For example: [{'name': 'foo', 'value': 'bar'}, {'name': 'baz', 'value': 'qux'}]
        ip_ranges: A list of comma separated ip ranges. Both IPv4 and IPv6 ranges are acceptable.
                    For example: "203.0.113.0/24,2001:db8:4a7f:a732/64"

    Returns:
        The Signed URL appended with the query parameters based on the
        specified URL prefix and configuration.
    """

    decoded_key = base64.urlsafe_b64decode(base64_key)
    algo = signature_algorithm.lower()

    # For most fields, the value we put in the token and the value we must sign
    # are the same.  The FullPath and Headers use a different string for the
    # value to be signed compared to the token.  To illustrate this difference,
    # we'll keep the token and the value to be signed separate.
    tokens = []
    to_sign = []

    # check for `full_path` or `path_globs` or `url_prefix`
    if full_path:
        tokens.append("FullPath")
        to_sign.append(f"FullPath={full_path}")
    elif path_globs:
        path_globs = path_globs.strip()
        field = f"PathGlobs={path_globs}"
        tokens.append(field)
        to_sign.append(field)
    elif url_prefix:
        field = "URLPrefix=" + base64_encoder(url_prefix.encode("utf-8"))
        tokens.append(field)
        to_sign.append(field)
    else:
        raise ValueError(
            "User Input Missing: One of `url_prefix`, `full_path` or `path_globs` must be specified"
        )

    # check & parse optional params
    if start_time:
        epoch_duration = start_time.astimezone(
            tz=datetime.timezone.utc
        ) - datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc)
        field = f"Starts={int(epoch_duration.total_seconds())}"
        tokens.append(field)
        to_sign.append(field)

    if not expiration_time:
        expiration_time = datetime.datetime.now() + datetime.timedelta(hours=1)
        epoch_duration = expiration_time.astimezone(
            tz=datetime.timezone.utc
        ) - datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc)
    else:
        epoch_duration = expiration_time.astimezone(
            tz=datetime.timezone.utc
        ) - datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc)
    field = f"Expires={int(epoch_duration.total_seconds())}"
    tokens.append(field)
    to_sign.append(field)

    if session_id:
        field = f"SessionID={session_id}"
        tokens.append(field)
        to_sign.append(field)

    if data:
        field = f"Data={data}"
        tokens.append(field)
        to_sign.append(field)

    if headers:
        header_names = []
        header_pairs = []
        for each in headers:
            header_names.append(each["name"])
            header_pairs.append("%s=%s" % (each["name"], each["value"]))
        tokens.append(f"Headers={','.join(header_names)}")
        to_sign.append(f"Headers={','.join(header_pairs)}")

    if ip_ranges:
        field = f"IPRanges={base64_encoder(ip_ranges.encode('ascii'))}"
        tokens.append(field)
        to_sign.append(field)

    # generating token
    to_sign = "~".join(to_sign)
    to_sign_bytes = to_sign.encode("utf-8")
    if algo == "ed25519":
        digest = ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key).sign(
            to_sign_bytes
        )
        tokens.append("Signature=" + base64_encoder(digest))
    elif algo == "sha256":
        signature = hmac.new(
            decoded_key, to_sign_bytes, digestmod=hashlib.sha256
        ).hexdigest()
        tokens.append("hmac=" + signature)
    elif algo == "sha1":
        signature = hmac.new(
            decoded_key, to_sign_bytes, digestmod=hashlib.sha1
        ).hexdigest()
        tokens.append("hmac=" + signature)
    else:
        raise ValueError(
            "Input Missing Error: `signature_algorithm` can only be one of `sha1`, `sha256` or `ed25519`"
        )
    return "~".join(tokens)

Java

Para autenticarte en Media CDN, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.bouncycastle.util.encoders.Hex;

public class DualToken {

  public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
    // TODO(developer): Replace these variables before running the sample.
    // Secret key as a base64 encoded string.
    byte[] base64Key = new byte[]{};
    // Algorithm can be one of these: SHA1, SHA256, or Ed25519.
    String signatureAlgorithm = "ed25519";
    // (Optional) Start time as a UTC datetime object.
    DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
    Optional<Instant> startTime = Optional.empty();
    // Expiration time as a UTC datetime object.
    // If None, an expiration time that's an hour after the current time is used.
    Instant expiresTime = Instant.from(formatter.parse("2022-09-13T12:00:00Z"));

    // ONE OF (`urlPrefix`, `fullPath`, `pathGlobs`) must be included in each input.
    // The URL prefix and protocol to sign.
    // For example: http://example.com/path/ for URLs under /path or http://example.com/path?param=1
    Optional<String> urlPrefix = Optional.empty();
    // A full path to sign, starting with the first '/'.
    // For example: /path/to/content.mp4
    Optional<String> fullPath = Optional.of("http://10.20.30.40/");
    // A set of path glob strings delimited by ',' or '!'.
    // For example: /tv/*!/film/* to sign paths starting with /tv/ or /film/ in any URL.
    Optional<String> pathGlobs = Optional.empty();

    // (Optional) A unique identifier for the session.
    Optional<String> sessionId = Optional.empty();
    // (Optional) Data payload to include in the token.
    Optional<String> data = Optional.empty();
    // (Optional) Header name and value to include in the signed token in name=value format.
    // May be specified more than once.
    // For example: [{'name': 'foo', 'value': 'bar'}, {'name': 'baz', 'value': 'qux'}]
    Optional<List<Header>> headers = Optional.empty();
    // (Optional) A list of comma-separated IP ranges. Both IPv4 and IPv6 ranges are acceptable.
    // For example: "203.0.113.0/24,2001:db8:4a7f:a732/64"
    Optional<String> ipRanges = Optional.empty();

    DualToken.signToken(
        base64Key,
        signatureAlgorithm,
        startTime,
        expiresTime,
        urlPrefix,
        fullPath,
        pathGlobs,
        sessionId,
        data,
        headers,
        ipRanges);
  }

  // Gets the signed URL suffix string for the Media CDN short token URL requests.
  // Result:
  //     The signed URL appended with the query parameters based on the
  // specified URL prefix and configuration.
  public static void signToken(
      byte[] base64Key, String signatureAlgorithm, Optional<Instant> startTime,
      Instant expirationTime, Optional<String> urlPrefix, Optional<String> fullPath,
      Optional<String> pathGlobs, Optional<String> sessionId, Optional<String> data,
      Optional<List<Header>> headers, Optional<String> ipRanges)
      throws NoSuchAlgorithmException, InvalidKeyException {

    String field = "";
    byte[] decodedKey = Base64.getUrlDecoder().decode(base64Key);

    // For most fields, the value in the token and the value to sign
    // are the same. Compared to the token, the FullPath and Headers
    // use a different string for the value to sign. To illustrate this difference,
    // we'll keep the token and the value to be signed separate.
    List<String> tokens = new ArrayList<>();
    List<String> toSign = new ArrayList<>();

    // Check for `fullPath` or `pathGlobs` or `urlPrefix`.
    if (fullPath.isPresent()) {
      tokens.add("FullPath");
      toSign.add(String.format("FullPath=%s", fullPath.get()));
    } else if (pathGlobs.isPresent()) {
      field = String.format("PathGlobs=%s", pathGlobs.get().trim());
      tokens.add(field);
      toSign.add(field);
    } else if (urlPrefix.isPresent()) {
      field = String.format("URLPrefix=%s",
          base64Encoder(urlPrefix.get().getBytes(StandardCharsets.UTF_8)));
      tokens.add(field);
      toSign.add(field);
    } else {
      throw new IllegalArgumentException(
          "User Input Missing: One of `urlPrefix`, `fullPath` or `pathGlobs` must be specified");
    }

    // Check & parse optional params.
    long epochDuration;
    if (startTime.isPresent()) {
      epochDuration = ChronoUnit.SECONDS.between(Instant.EPOCH, startTime.get());
      field = String.format("Starts=%s", epochDuration);
      tokens.add(field);
      toSign.add(field);
    }

    if (expirationTime == null) {
      expirationTime = Instant.now().plus(1, ChronoUnit.HOURS);
    }
    epochDuration = ChronoUnit.SECONDS.between(Instant.EPOCH, expirationTime);
    field = String.format("Expires=%s", epochDuration);
    tokens.add(field);
    toSign.add(field);

    if (sessionId.isPresent()) {
      field = String.format("SessionID=%s", sessionId.get());
      tokens.add(field);
      toSign.add(field);
    }

    if (data.isPresent()) {
      field = String.format("Data=%s", data.get());
      tokens.add(field);
      toSign.add(field);
    }

    if (headers.isPresent()) {
      List<String> headerNames = new ArrayList<>();
      List<String> headerPairs = new ArrayList<>();

      for (Header entry : headers.get()) {
        headerNames.add(entry.getName());
        headerPairs.add(String.format("%s=%s", entry.getName(), entry.getValue()));
      }
      tokens.add(String.format("Headers=%s", String.join(",", headerNames)));
      toSign.add(String.format("Headers=%s", String.join(",", headerPairs)));
    }

    if (ipRanges.isPresent()) {
      field = String.format("IPRanges=%s",
          base64Encoder(ipRanges.get().getBytes(StandardCharsets.US_ASCII)));
      tokens.add(field);
      toSign.add(field);
    }

    // Generate token.
    String toSignJoined = String.join("~", toSign);
    byte[] toSignBytes = toSignJoined.getBytes(StandardCharsets.UTF_8);
    String algorithm = signatureAlgorithm.toLowerCase();

    if (algorithm.equalsIgnoreCase("ed25519")) {
      Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(decodedKey, 0);
      Ed25519Signer signer = new Ed25519Signer();
      signer.init(true, privateKey);
      signer.update(toSignBytes, 0, toSignBytes.length);
      byte[] signature = signer.generateSignature();
      tokens.add(String.format("Signature=%s", base64Encoder(signature)));
    } else if (algorithm.equalsIgnoreCase("sha256")) {
      String sha256 = "HmacSHA256";
      Mac mac = Mac.getInstance(sha256);
      SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, sha256);
      mac.init(secretKeySpec);
      byte[] signature = mac.doFinal(toSignBytes);
      tokens.add(String.format("hmac=%s", Hex.toHexString(signature)));
    } else if (algorithm.equalsIgnoreCase("sha1")) {
      String sha1 = "HmacSHA1";
      Mac mac = Mac.getInstance(sha1);
      SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, sha1);
      mac.init(secretKeySpec);
      byte[] signature = mac.doFinal(toSignBytes);
      tokens.add(String.format("hmac=%s", Hex.toHexString(signature)));
    } else {
      throw new Error(
          "Input Missing Error: `signatureAlgorithm` can only be one of `sha1`, `sha256` or "
              + "`ed25519`");
    }
    // The signed URL appended with the query parameters based on the
    // specified URL prefix and configuration.
    System.out.println(String.join("~", tokens));
  }

  // Returns a base64-encoded string compatible with Media CDN.
  // Media CDN uses URL-safe base64 encoding and strips off the padding at the
  // end.
  public static String base64Encoder(byte[] value) {
    byte[] encodedBytes = Base64.getUrlEncoder().withoutPadding().encode(value);
    return new String(encodedBytes, StandardCharsets.UTF_8);
  }

  public static class Header {

    private String name;
    private String value;

    public Header(String name, String value) {
      this.name = name;
      this.value = value;
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    @Override
    public String toString() {
      return "Header{"
          + "name='" + name + '\''
          + ", value='" + value + '\''
          + '}';
    }
  }

}

En las siguientes secciones, se describen los campos que usan los tokens.

Campos de token obligatorios

Los siguientes campos son obligatorios para cada token:

  • Expires
  • Uno de los siguientes:
    • PathGlobs
    • URLPrefix
    • FullPath
  • Una de las siguientes opciones:
    • Signature
    • hmac

A menos que se especifique lo contrario, los nombres de los parámetros y sus valores distinguen mayúsculas de minúsculas.

En la siguiente tabla, se explica cada parámetro:

Nombre y alias del campo Parámetros de token Valor con firma

Expires

exp

Segundos de número entero que transcurrieron desde el tiempo Unix (1970-01-01T00:00:00Z) Expires=EXPIRATION_TIME, después de lo cual se produce el token ya no es válido.

PathGlobs

paths, acl

Una lista de hasta cinco segmentos de ruta de acceso a los que se debe otorgar acceso. Los segmentos pueden estar delimitadas por comas (,) o signos de exclamación !, pero no ambas.

PathGlobs admite comodines en las rutas de acceso mediante el uso de asteriscos (*) y signos de interrogación (?). Un solo carácter de asterisco (*) abarca cualquier cantidad de segmentos de ruta, a diferencia de la sintaxis de coincidencia de patrones para pathMatchTemplate.

No se permiten los parámetros de ruta de acceso, que se indican con punto y coma (;), porque crean ambigüedad durante la coincidencia.

Por estos motivos, asegúrate de que tu URL no contenga los siguientes caracteres especiales: ,!*?;

PathGlobs=PATHS
URLPrefix

Una URL codificada en base64 segura para la Web que incluya el protocolo http:// o https:// hasta un punto que elijas

Por ejemplo, algunos valores válidos de URLPrefix para `https://example.com/foo/bar.ts` son `https://example.com`, `https://example.com/foo` y `https://example.com/foo/bar`.

URLPrefix=BASE_64_URL_PREFIX
FullPath Ninguno Cuando especifiques FullPath en un token, no dupliques la ruta que especificaste en el valor firmado. En un token, incluye el campo sin un =. FullPath=FULL_PATH_TO_OBJECT
Signature Una versión de la firma codificada en base64 segura para la Web. No aplicable
hmac Una versión del valor HMAC codificada en base64 segura para la Web. No aplicable

Sintaxis de comodines PathGlobs

En la siguiente tabla, se explica la sintaxis de comodines PathGlobs.

Operador Coincidencias Ejemplos
* (asterisco) Coincide con cero o más caracteres en la ruta de acceso de la URL, incluidos los siguientes: caracteres de barra diagonal (/).
  • /videos/* coincide con cualquier ruta que comience con /videos/
  • /videos/s*/4k/* coincide con /videos/s/4k/ y /videos/s01/4k/main.m3u8.
  • /manifests/*/4k/* coincide con /manifests/s01/4k/main.m3u8 y /manifests/s01/e01/4k/main.m3u8. No coincide con /manifests/4k/main.m3u8.
? (signo de interrogación) Coincide con un solo carácter de La ruta de la URL, sin incluir la barra diagonal (/) caracteres. /videos/s?main.m3u8 coincidencias /videos/s1main.m3u8 No coincide con /videos/s01main.m3u8 ni /videos/s/main.m3u8.

Los signos glob deben comenzar con un asterisco (*) o una barra diagonal (/) para las rutas de URL.

Debido a que * y /* coinciden con todas las rutas de URL, no te recomendamos usando cualquiera de ellos en tus tokens firmados. Para obtener la máxima protección, y asegúrate de que tus globs coincidan con el contenido al que quieres otorgar acceso.

Campos de token opcionales

A menos que se especifique lo contrario, los nombres de los parámetros y sus valores distinguen mayúsculas de minúsculas.

La siguiente tabla explica los nombres de los parámetros, los alias y los detalles de parámetros opcionales:

Nombre y alias del campo Parámetros Valor con firma

Starts

st

Números enteros de segundos desde el tiempo Unix (1970-01-01T00:00:00Z) Starts=START_TIME
IPRanges

Una lista de hasta cinco direcciones IPv4 e IPv6 en formato CIDR para que esta URL es válida en formato Base64 seguro para la Web. Por ejemplo: para especificar los rangos de IP “192.6.13.13/32,193.5.64.135/32”, deberás especificar IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy

Puede no ser útil incluir IPRanges en los tokens cuando los clientes en riesgo de migraciones de WAN o casos en los que la ruta de red a tu frontend de la aplicación es diferente de la ruta de entrega. Media CDN rechaza a los clientes con un código HTTP 403 cuando se conectan con una dirección IP que no forma parte de la solicitud firmada.

Los siguientes son casos que pueden provocar que Media CDN rechace a los clientes con un código HTTP 403:

  • Entornos de doble pila (IPv4, IPv6)
  • Migración de conexión (Wi-Fi a móvil y de móvil a Wi-Fi)
  • Redes móviles que usan NAT de puerta de enlace del proveedor (CGNAT o CGN)
  • TCP de varias rutas (MPTCP)

Todos estos factores pueden contribuir a que un cliente determinado tenga una dirección IP no determinista durante una sesión de reproducción de video. Si la dirección IP del cliente cambia después de que emites el acceso y el cliente intenta descargar un segmento de video en su búfer de reproducción, recibe un HTTP 403 de Media CDN.

IPRanges=BASE_64_IP_RANGES

SessionID

id

Es una cadena arbitraria, útil para el análisis de registros o el seguimiento de reproducción.

Para evitar crear un token no válido, usa cadenas codificadas en Base64 con codificación % o seguras para la Web. Los siguientes caracteres no deben usarse para SessionID, ya que provocan que el token no sea válido: "~", "&" o " " (espacio).

SessionID=SESSION_ID_VALUE

Data

data, payload

Una cadena arbitraria, útil para el análisis de registros.

Para evitar crear un token no válido, usa cadenas codificadas en Base64 con codificación % o seguras para la Web. Los siguientes caracteres no deben usarse para Data, ya que provocan que el token no sea válido: "~", "&" o " " (espacio).

data=DATA_VALUE
Headers Una lista delimitada por comas de nombres de campos de encabezado. Los nombres de encabezado son no distingue mayúsculas de minúsculas para las búsquedas en la solicitud. Los nombres de los encabezados los valores distinguen mayúsculas de minúsculas. Si falta un encabezado, el valor es el campo una cadena vacía. Si hay varias copias de un encabezado, se usan y coma concatenadas. Headers=HEADER_1_NAME=HEADER_1_EXPECTED_VALUE, HEADER_2_NAME=HEADER_2_EXPECTED_VALUE

Ejemplos

En las siguientes secciones, se muestran ejemplos de generación de tokens.

Ejemplo de uso de FullPath

Considera el siguiente ejemplo con el campo FullPath:

  • Elemento solicitado: http://example.com/tv/my-show/s01/e01/playlist.m3u8
  • Hora de vencimiento: 160000000

El valor con firma es el siguiente:

Expires=160000000~FullPath=/tv/my-show/s01/e01/playlist.m3u8

Para crear un token, firma el valor firmado con una firma Ed25519 o con una con clave simétrica o HMAC.

Los siguientes son ejemplos de tokens creados a partir de un valor firmado:

Firma Ed25519

Expires=160000000~FullPath~Signature=SIGNATURE_OF_SIGNED_VALUE

Donde SIGNATURE_OF_SIGNED_VALUE es la firma ED25519 del valor firmado y creado previamente.

HMAC de clave simétrica

Expires=160000000~FullPath~hmac=HMAC_OF_SIGNED_VALUE

Donde HMAC_OF_SIGNED_VALUE es la HMAC de clave simétrica del objeto firmado valor creado previamente.

En los ejemplos anteriores, se proporciona FullPath en el token, pero el valor no se repita desde la ruta especificada en el valor firmado. Esto te permite firmar la ruta de acceso completa de la solicitud sin duplicar la solicitud en el token.

Ejemplo de uso de URLPrefix

Considera el siguiente ejemplo con el campo URLPrefix:

  • Elemento solicitado: http://example.com/tv/my-show/s01/e01/playlist.m3u8
  • Hora de vencimiento: 160000000

El valor con firma es el siguiente:

Expires=160000000~URLPrefix=aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4

En el ejemplo anterior, reemplazamos la ruta al elemento solicitado, http://example.com/tv/my-show/s01/e01/playlist.m3u8 por la ruta de acceso al elemento en formato Base64 seguro para la Web aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4

Para crear un token, firma el valor firmado con una firma Ed25519 o con una con clave simétrica o HMAC.

Los siguientes son ejemplos de tokens creados a partir de un valor firmado:

Firma Ed25519

Expires=160000000~URLPrefix=aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4~Signature=SIGNATURE_OF_SIGNED_VALUE

Donde SIGNATURE_OF_SIGNED_VALUE es la firma ED25519 del valor firmado y creado previamente.

HMAC de clave simétrica

Expires=160000000~URLPrefix=aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4~hmac=HMAC_OF_SIGNED_VALUE

Donde HMAC_OF_SIGNED_VALUE es la HMAC de clave simétrica del objeto firmado valor creado previamente.

Ejemplo de uso de Headers

Considera el siguiente ejemplo con el campo Headers:

  • Elemento solicitado: http://example.com/tv/my-show/s01/e01/playlist.m3u8
  • Hora de vencimiento: 160000000
  • Valor de PathGlobs: *
  • Encabezados de solicitud esperados:
    • user-agent: browser
    • accept: text/html

El valor con firma es el siguiente:

Expires=160000000~PathGlobs=*~Headers=user-agent=browser,accept=text/html

Para crear un token, firma el valor firmado con una firma Ed25519 o con una con clave simétrica o HMAC.

Los siguientes son ejemplos de tokens creados a partir de un valor firmado:

Firma Ed25519

Expires=160000000~PathGlobs=*~Headers=user-agent,accept~Signature=SIGNATURE_OF_SIGNED_VALUE

Donde SIGNATURE_OF_SIGNED_VALUE es la firma ED25519 del valor firmado y creado previamente.

HMAC de clave simétrica

Expires=160000000~PathGlobs=*~Headers=user-agent,accept~hmac=HMAC_OF_SIGNED_VALUE

Donde HMAC_OF_SIGNED_VALUE es la HMAC de clave simétrica del objeto firmado valor creado previamente.

En los ejemplos anteriores, se proporciona Headers=user-agent,accept en el token. pero los valores de encabezado esperados no se repiten a partir del valor firmado. Esto te permite firmar pares clave-valor específicos del encabezado de la solicitud sin duplicar los valores en el token.