Tokens generieren

In dieser Anleitung wird erklärt, wie Sie ein Token generieren und welche Felder für Tokens erforderlich und optional sind.

Zum Erstellen eines Tokens erstellen Sie einen String, der signiert werden soll. In dieser Anleitung wird er als signierter Wert bezeichnet. Der signierte Wert enthält Parameter, die den Inhalt beschreiben, den Sie schützen, die Ablaufzeit des signierten Werts usw.

Sie verwenden den signierten Wert beim Erstellen eines Token-Strings. Zum Erstellen eines Token-Strings erstellen Sie die Parameter für das Token, z. B. einen Hash-basierten Message Authentication Code (HMAC) mit symmetrischem Schlüssel des signierten Werts.

Media CDN verwendet das endgültige zusammengesetzte Token, um Ihre Inhalte zu schützen.

Token erstellen

  1. Erstellen Sie einen signierten Wert, indem Sie einen String verketten, der die erforderlichen Tokenfelder und die gewünschten optionalen Token felder enthält. Trennen Sie die einzelnen Felder und Parameter durch eine Tilde ~.

  2. Signieren Sie den signierten Wert entweder mit einer Ed25519-Signatur oder einem symmetrischen HMAC-Schlüssel.

  3. Erstellen Sie das Token, indem Sie einen String verketten, der die erforderlichen Tokenfelder und optionalen Tokenfelder enthält. Trennen Sie die einzelnen Felder und Parameter durch eine Tilde ~.

    Beim Erstellen des Tokens sind die Werte für die einzelnen Parameter zwischen dem signierten Wert und dem Token-String identisch, mit folgenden Ausnahmen:

    • FullPath
    • Headers

Das folgende Codebeispiel zeigt, wie Sie ein Token programmatisch erstellen:

Python

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Media CDN zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

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

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Media CDN zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.


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 + '\''
          + '}';
    }
  }

}

In den folgenden Abschnitten werden die von Tokens verwendeten Felder beschrieben.

Erforderliche Tokenfelder

Die folgenden Felder sind für jedes Token erforderlich:

  • Expires
  • Eines der folgenden Felder:
    • PathGlobs
    • URLPrefix
    • FullPath
  • Eines der folgenden Felder:
    • Signature
    • hmac

Wenn nicht anders angegeben, wird bei Parameternamen und ihren Werten die Groß-/Kleinschreibung beachtet.

In der folgenden Tabelle wird jeder Parameter erläutert:

Feldname / Aliase Tokenparameter Signierter Wert

Expires

exp

Ganzzahlsekunden, die seit der Unix-Epoche verstrichen sind (1970-01-01T00:00:00Z) Expires=EXPIRATION_TIME, danach ist das Token nicht mehr gültig.

PathGlobs

paths, acl

Eine Liste mit bis zu fünf Pfadsegmenten, für die Zugriff gewährt werden soll. Die Segmente können durch Kommas (,) oder Ausrufezeichen (!) getrennt werden, aber nicht durch beides.

PathGlobs unterstützt Platzhalter in Pfaden mit Sternchen (*) und Fragezeichen (?). Ein einzelnes Sternchen (*) umfasst eine beliebige Anzahl von Pfadsegmenten, anders als die Syntax für den Musterabgleich für pathMatchTemplate.

Pfadparameter, die mit Semikolons (;) gekennzeichnet sind, sind nicht zulässig, da sie beim Abgleich zu Mehrdeutigkeiten führen.

Aus diesen Gründen darf Ihre URL die folgenden Sonderzeichen nicht enthalten: ,!*?;

PathGlobs=PATHS
URLPrefix

Eine websichere, mit Base64 codierte URL einschließlich des Protokolls http:// oder https:// bis zu einem von Ihnen gewählten Punkt.

Beispiele für gültige URLPrefix-Werte für `https://example.com/foo/bar.ts` sind `https://example.com`, `https://example.com/foo` und `https://example.com/foo/bar`.

URLPrefix=BASE_64_URL_PREFIX
FullPath – Wenn Sie FullPath in einem Token angeben, duplizieren Sie den Pfad nicht, den Sie im signierten Wert angegeben haben. Fügen Sie in einem Token den Feld namen ohne ein = ein. FullPath=FULL_PATH_TO_OBJECT
Signature Eine websichere, mit Base64 codierte Version der Signatur. Nicht zutreffend
hmac Eine websichere, mit Base64 codierte Version des HMAC-Werts. Nicht zutreffend

Platzhaltersyntax für PathGlobs

In der folgenden Tabelle wird die Platzhaltersyntax für PathGlobs erläutert.

Operator Stimmt überein mit Beispiele
* (Sternchen) Entspricht null oder mehr Zeichen im Pfad der URL, einschließlich Schrägstrichen (/).
  • /videos/* entspricht jedem Pfad, der mit /videos/ beginnt.
  • /videos/s*/4k/* entspricht /videos/s/4k/ und /videos/s01/4k/main.m3u8.
  • /manifests/*/4k/* entspricht /manifests/s01/4k/main.m3u8 und /manifests/s01/e01/4k/main.m3u8. Es entspricht nicht /manifests/4k/main.m3u8.
? (Fragezeichen) Entspricht einem einzelnen Zeichen im Pfad der URL, ohne Schrägstriche (/) /videos/s?main.m3u8 entspricht /videos/s1main.m3u8. Es entspricht weder /videos/s01main.m3u8 noch /videos/s/main.m3u8.

Globs müssen für URL-Pfade entweder mit einem Sternchen (*) oder einem Schrägstrich (/) beginnen.

Da * und /* mit allen URL-Pfaden übereinstimmen, empfehlen wir, sie nicht in Ihren signierten Tokens zu verwenden. Für maximalen Schutz müssen Ihre Globs mit den Inhalten übereinstimmen, für die Sie Zugriff gewähren möchten.

Optionale Tokenfelder

Wenn nicht anders angegeben, wird bei Parameternamen und ihren Werten die Groß-/Kleinschreibung beachtet.

In der folgenden Tabelle werden Parameternamen, Aliase und Details für optionale Parameter erläutert:

Feldname / Aliase Parameter Signierter Wert

Starts

st

Ganzzahlsekunden seit der Unix-Epoche (1970-01-01T00:00:00Z) Starts=START_TIME
IPRanges

Eine Liste mit bis zu fünf IPv4- und IPv6-Adressen im CIDR-Format, für die diese URL im websicheren Base64-Format gültig ist. Wenn Sie beispielsweise die IP-Bereiche „192.6.13.13/32,193.5.64.135/32“ angeben möchten, geben Sie IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy an.

Die Aufnahme von IPRanges in die Tokens ist möglicherweise nicht sinnvoll, wenn Kunden von WAN-Migrationen bedroht sind oder wenn der Netzwerkpfad zu Ihrem Anwendungs-Frontend ein anderer ist als der Bereitstellungspfad. Media CDN lehnt Clients mit dem Code HTTP 403 ab, wenn sie eine Verbindung mit einer IP-Adresse herstellen, die nicht Teil der signierten Anfrage ist.

In den folgenden Fällen kann es vorkommen, dass Media CDN Clients mit dem Code HTTP 403 ablehnt:

  • Dual-Stack-Umgebungen (IPv4, IPv6)
  • Verbindungsmigration (WLAN zu Mobilfunk und Mobilfunk zu WLAN)
  • Mobilfunknetze, die Carrier-Grade NAT (CGNAT oder CGN) verwenden
  • Multi-Path TCP (MPTCP)

All diese Faktoren können dazu beitragen, dass ein bestimmter Client während einer Videowiedergabesitzung eine nicht-deterministische IP-Adresse hat. Wenn sich die IP-Adresse des Clients ändert, nachdem Sie den Zugriff gewährt haben, und der Client dann versucht, ein Videosegment in seinen Wiedergabepuffer herunterzuladen, erhält er von Media CDN den Fehler HTTP 403.

IPRanges=BASE_64_IP_RANGES

SessionID

id

Ein beliebiger String, der für die Loganalyse oder die Wiedergabeverfolgung nützlich ist.

Verwenden Sie %-codierte oder websichere mit Base64 codierte Strings, um ein ungültiges Token zu vermeiden. Die folgenden Zeichen dürfen nicht für SessionID verwendet werden, da sie dazu führen, dass das Token ungültig ist: "~", "&" oder " " (Leerzeichen).

SessionID=SESSION_ID_VALUE

Data

data, payload

Ein beliebiger String, der für die Loganalyse nützlich ist.

Verwenden Sie %-codierte oder websichere mit Base64 codierte Strings, um ein ungültiges Token zu vermeiden. Die folgenden Zeichen dürfen nicht für Data, verwendet werden, da sie dazu führen, dass das Token ungültig ist: "~", "&", oder " " (Leerzeichen).

data=DATA_VALUE
Headers Eine durch Kommas getrennte Liste von Header-Feldnamen. Bei Header-Namen wird bei der Suche in der Anfrage die Groß-/Kleinschreibung nicht beachtet. Bei Header-Namen in den signierten Werten wird die Groß-/Kleinschreibung beachtet. Wenn ein Header fehlt, ist der Wert ein leerer String. Wenn mehrere Kopien eines Headers vorhanden sind, werden sie durch Kommas getrennt verkettet. Headers=HEADER_1_NAME=HEADER_1_EXPECTED_VALUE, HEADER_2_NAME=HEADER_2_EXPECTED_VALUE

Beispiele

In den folgenden Abschnitten finden Sie Beispiele für das Generieren von Tokens.

Beispiel mit FullPath

Sehen Sie sich das folgende Beispiel mit dem Feld FullPath an:

  • Angefragtes Element: http://example.com/tv/my-show/s01/e01/playlist.m3u8
  • Ablaufzeit: 160000000

Der signierte Wert ist:

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

Um ein Token zu erstellen, signieren Sie den signierten Wert entweder mit einer Ed25519-Signatur oder einem symmetrischen HMAC-Schlüssel.

Im Folgenden finden Sie Beispiel-Tokens, die aus einem signierten Wert erstellt wurden:

Ed25519-Signatur

Expires=160000000~FullPath~Signature=SIGNATURE_OF_SIGNED_VALUE

Dabei ist SIGNATURE_OF_SIGNED_VALUE die Ed25519-Signatur des zuvor erstellten signierten Werts.

Symmetrischer HMAC-Schlüssel

Expires=160000000~FullPath~hmac=HMAC_OF_SIGNED_VALUE

Dabei ist HMAC_OF_SIGNED_VALUE der symmetrische HMAC-Schlüssel des zuvor erstellten signierten Werts.

In den vorherigen Beispielen wird FullPath im Token angegeben, der Wert wird aber nicht aus dem im signierten Wert angegebenen Pfad wiederholt. So können Sie den vollständigen Pfad der Anfrage signieren, ohne die Anfrage im Token zu duplizieren.

Beispiel mit URLPrefix

Sehen Sie sich das folgende Beispiel mit dem Feld URLPrefix an:

  • Angefragtes Element: http://example.com/tv/my-show/s01/e01/playlist.m3u8
  • Ablaufzeit: 160000000

Der signierte Wert ist:

Expires=160000000~URLPrefix=aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4

Im vorherigen Beispiel haben wir den Pfad zum angeforderten Element, http://example.com/tv/my-show/s01/e01/playlist.m3u8, durch den Pfad zum Element im websicheren Base64-Format ersetzt: aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4.

Um ein Token zu erstellen, signieren Sie den signierten Wert entweder mit einer Ed25519-Signatur oder einem symmetrischen HMAC-Schlüssel.

Im Folgenden finden Sie Beispiel-Tokens, die aus einem signierten Wert erstellt wurden:

Ed25519-Signatur

Expires=160000000~URLPrefix=aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4~Signature=SIGNATURE_OF_SIGNED_VALUE

Dabei ist SIGNATURE_OF_SIGNED_VALUE die Ed25519-Signatur des zuvor erstellten signierten Werts.

Symmetrischer HMAC-Schlüssel

Expires=160000000~URLPrefix=aHR0cDovL2V4YW1wbGUuY29tL3R2L215LXNob3cvczAxL2UwMS9wbGF5bGlzdC5tM3U4~hmac=HMAC_OF_SIGNED_VALUE

Dabei ist HMAC_OF_SIGNED_VALUE der symmetrische HMAC-Schlüssel des zuvor erstellten signierten Werts.

Beispiel mit Headers

Sehen Sie sich das folgende Beispiel mit dem Feld Headers an:

  • Angefragtes Element: http://example.com/tv/my-show/s01/e01/playlist.m3u8
  • Ablaufzeit: 160000000
  • PathGlobs-Wert: *
  • Erwartete Anfrageheader:
    • user-agent: browser
    • accept: text/html

Der signierte Wert ist:

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

Um ein Token zu erstellen, signieren Sie den signierten Wert entweder mit einer Ed25519-Signatur oder einem symmetrischen HMAC-Schlüssel.

Im Folgenden finden Sie Beispiel-Tokens, die aus einem signierten Wert erstellt wurden:

Ed25519-Signatur

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

Dabei ist SIGNATURE_OF_SIGNED_VALUE die Ed25519-Signatur des zuvor erstellten signierten Werts.

Symmetrischer HMAC-Schlüssel

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

Dabei ist HMAC_OF_SIGNED_VALUE der symmetrische HMAC-Schlüssel des zuvor erstellten signierten Werts.

In den vorherigen Beispielen wird Headers=user-agent,accept im Token angegeben, die erwarteten Header-Werte werden aber nicht aus dem signierten Wert wiederholt. So können Sie bestimmte Schlüssel/Wert-Paare für Anfrageheader signieren, ohne die Werte im Token zu duplizieren.