Contacta con el soporte | Estado del sistema
Contenido de la página

    Creando un Token web JSON (JWT)

    En este tema, aprenderá a crear un Token web JSON (JWT) que se puede utilizar al comunicarse con Brightcove Playback API.

    Introducción

    Para agregar un nivel adicional de protección al acceder a su biblioteca de videos, o para aplicar restricciones de nivel de usuario para su contenido, puede pasar un Token web JSON (JWT) con su llamada a Brightcove Playback API. Para crear el token, siga estos pasos:

    1. Generar par de claves público-privadas
    2. Registre la clave pública con Brightcove
    3. Crear un Token web JSON
    4. Prueba de reproducción

    Generar par de claves público-privadas

    El editor generará un par de claves pública-privada y proporcionará la clave pública a Brightcove. El editor utiliza la clave privada para firmar tokens y no se comparte con Brightcove.

    Hay muchas formas de generar el par de claves pública-privada. Aquí hay unos ejemplos:

    Ejemplo de script de bash:

    Script de ejemplo para generar el par de claves:

    #!/bin/bash
    set -euo pipefail
    
    NAME=${1:-}
    test -z "${NAME:-}" && NAME="brightcove-playback-auth-key-$(date +%s)"
    mkdir "$NAME"
    
    PRIVATE_PEM="./$NAME/private.pem"
    PUBLIC_PEM="./$NAME/public.pem"
    PUBLIC_TXT="./$NAME/public_key.txt"
    
    ssh-keygen -t rsa -b 2048 -m PEM -f "$PRIVATE_PEM" -q -N ""
    openssl rsa -in "$PRIVATE_PEM" -pubout -outform PEM -out "$PUBLIC_PEM" 2>/dev/null
    openssl rsa -in "$PRIVATE_PEM" -pubout -outform DER | base64 > "$PUBLIC_TXT"
    
    rm "$PRIVATE_PEM".pub
    
    echo "Public key to saved in $PUBLIC_TXT"
    

    Ejecute el script:

    $ bash keygen.sh
    

    Ejemplo usando Ir

    Ejemplo usando el Ir lenguaje de programación para generar el par de claves:

    package main
    
    import (
    	"crypto/rand"
    	"crypto/rsa"
    	"crypto/x509"
    	"encoding/base64"
    	"encoding/pem"
    	"flag"
    	"fmt"
    	"io/ioutil"
    	"os"
    	"path"
    	"strconv"
    	"time"
    )
    
    func main() {
    	var out string
    
    	flag.StringVar(&out, "output-dir", "", "Output directory to write files into")
    	flag.Parse()
    
    	if out == "" {
    		out = "rsa-key_" + strconv.FormatInt(time.Now().Unix(), 10)
    	}
    
    	if err := os.MkdirAll(out, os.ModePerm); err != nil {
    		panic(err.Error())
    	}
    
    	priv, err := rsa.GenerateKey(rand.Reader, 2048)
    	if err != nil {
    		panic(err.Error())
    	}
    
    	privBytes := x509.MarshalPKCS1PrivateKey(priv)
    
    	pubBytes, err := x509.MarshalPKIXPublicKey(priv.Public())
    	if err != nil {
    		panic(err.Error())
    	}
    
    	privOut, err := os.OpenFile(path.Join(out, "private.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
    	if err != nil {
    		panic(err.Error())
    	}
    
    	if err := pem.Encode(privOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}); err != nil {
    		panic(err.Error())
    	}
    
    	pubOut, err := os.OpenFile(path.Join(out, "public.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
    	if err != nil {
    		panic(err.Error())
    	}
    
    	if err := pem.Encode(pubOut, &pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}); err != nil {
    		panic(err.Error())
    	}
    
    	var pubEnc = base64.StdEncoding.EncodeToString(pubBytes)
    
    	var pubEncOut = path.Join(out, "public_key.txt")
    	if err := ioutil.WriteFile(pubEncOut, []byte(pubEnc+"\n"), 0600); err != nil {
    		panic(err.Error())
    	}
    
    	fmt.Println("Public key saved in " + pubEncOut)
    }
    
    <

    Ejemplo usando node.js

    Ejemplo usando node.js para generar el par de claves:

    var crypto = require("crypto");
    var fs = require("fs");
    
    var now = Math.floor(new Date() / 1000);
    var dir = "rsa-key_" + now;
    fs.mkdirSync(dir);
    
    crypto.generateKeyPair(
      "rsa",
      {modulusLength: 2048},
      (err, publicKey, privateKey) => {
        fs.writeFile(
          dir + "/public.pem",
          publicKey.export({ type: "spki", format: "pem" }),
          err => {}
        );
        fs.writeFile(
          dir + "/public_key.txt",
          publicKey.export({ type: "spki", format: "der" }).toString("base64") +
            "\n",
          err => {}
        );
        fs.writeFile(
          dir + "/private.pem",
          privateKey.export({ type: "pkcs1", format: "pem" }),
          err => {}
        );
      }
    );
    
    console.log("Public key saved in " + dir + "/public_key.txt");

    Registrar clave pública

    Utilizará la API de claves para registrar su clave pública con Brightcove.

    API clave

    La API de claves se utiliza para administrar sus claves públicas con Brightcove.

    URL base

    La URL base de la API es:

    https://playback-auth.api.brightcove.com

    Ruta de la cuenta

    En todos los casos, se realizarán solicitudes para una cuenta de Video Cloud específica. Por lo tanto, siempre agregará el término cuentas seguido de la identificación de su cuenta a la URL base:

    https://playback-auth.api.brightcove.com/v1/accounts/{accountID}

    Autorización

    Se requiere un token de acceso para las solicitudes y debe estar presente en el encabezado de Autorización:

    Authorization: Bearer {access_token}

    El token de acceso es un token de acceso OAuth2 temporal que debe obtenerse del servicio Brightcove OAuth. Para obtener detalles sobre cómo obtener credenciales de cliente y usarlas para recuperar tokens de acceso, consulte la Descripción general de Brightcove OAuth.

    Permisos

    Las solicitudes a la API clave deben realizarse desde credenciales del cliente con los siguientes permisos:

    • video-cloud/playback-auth/key/read
    • video-cloud/playback-auth/key/write

    Administrar claves

    La API clave admite las siguientes solicitudes:

    Registre una nueva clave:

    Pon el valor de tu clave pública en el cuerpo de la solicitud de API. Puede encontrar la clave en el public_key.txt expediente.

    Pedido
    POST /v1/accounts/{accountID}/keys
        Content-Type: application/json
        Body: {"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj...MyeQviqploA=="}
    

    Usando Curl

    curl -X POST \\ -H "Tipo de contenido: aplicación / json" \\ -H "Autorización: Portador {access_token} "\ -d '{"value": "{your_public_key_value}«}' \ https://playback-auth.api.brightcove.com/v1/accounts/{accountID}/keys 
    Respuesta
    {
      "id": "{your_public_key_id}",
      "type": "public",
      "algorithm": "rsa",
      "value": "{your_public_key_value}",
      "createdAt": "2020-01-03T20:30:36.488Z"
    }

    Lista de claves:

    Obtenga una lista de claves públicas en su cuenta.

    GET /v1/accounts/{accountID}/keys

    Obtenga una clave:

    Obtenga los detalles de una clave pública en su cuenta.

    GET /v1/accounts/{accountID}/keys/{key_Id}

    Eliminar una clave:

    Elimina una clave pública de tu cuenta.

    DELETE /v1/accounts/{accountID}/keys/{key_Id}

    Crear un Token web JSON

    Los editores crean un Token web JSON (JWT). El token está firmado con el algoritmo RSA utilizando el algoritmo hash SHA-256 (identificado en la especificación JWT como "RS256") No se admitirán otros algoritmos JWT.

    Un subconjunto del estándar Reclamaciones de JSON Web Token se utilizará, junto con algunas reclamaciones privadas definidas por Brightcove. Crearás un Token web JSON firmado con su clave privada.

    Reclamaciones de entrega de URL estáticas

    Para obtener una lista de afirmaciones que se pueden utilizar, consulte la Entrega de URL estática documento.

    Reclamaciones de autorización de reproducción

    Las siguientes afirmaciones se pueden utilizar con Servicio de autorización de reproducción de Brightcove.

    Campo Tipo Necesario Descripción
    accid Cuerda La identificación de la cuenta que posee el contenido que se está reproduciendo.
    exp Entero Hora en que esta ficha ya no será válida, en segundos desde la Época. No debe ser más de 30 días desde iat
    iat Entero Hora en que se emitió esta ficha, en segundos desde la Época
    conid Cuerda Si está presente, este token solo autorizará la obtención de licencias para una identificación de video de Video Cloud específica.

    Debe ser una identificación de video válida.
    maxip Entero Si está presente, este token solo podrá ser utilizado por esta cantidad de direcciones IP diferentes. (DRM y AES-128)

    Requerido para el seguimiento de la sesión.
    maxu Entero Si está presente, este token solo será válido para esta cantidad de solicitudes de licencia. (DRM y AES-128)

    • Para HLSe, los reproductores realizarán múltiples solicitudes al reproducir un video, generalmente una por reproducción. La maxu debe establecerse lo suficientemente alto para tener en cuenta estas solicitudes adicionales.
    • Para DRM, se realiza una solicitud de licencia por reproducción
    Requerido para el seguimiento de la sesión.
    ua Cuerda Si está presente, este token solo será válido para solicitudes de este agente de usuario.

    Este campo no está validado.

    Reclamaciones de derechos de reproducción

    Las siguientes afirmaciones se pueden utilizar con Servicio de gestión de derechos de reproducción de Brightcove.

    Campo Tipo Necesario Obligatorio para los límites de transmisión simultánea Solo DRM Descripción
    accid Cuerda La identificación de la cuenta que posee el contenido que se está reproduciendo.
    exp Entero Hora en que esta ficha ya no será válida, en segundos desde la Época. No debe ser más de 30 días desde iat
    iat Entero Hora en que se emitió esta ficha, en segundos desde la Época
    nbf Entero Hora en que esta ficha comenzará a ser válida, en segundos desde la Época.
    pkid Cuerda La identificación de clave pública utilizada para verificar este token. Está registrado en el Servicio de autorización de reproducción de Brightcove y debe utilizar el formato de clave RSA.

    Si pkid se especifica, validamos el token con la clave especificada.

    Si no pkid se especifica, recuperamos todas las claves de la cuenta e intentamos validarlas con todas.
    prid Cuerda A playback_rights_id. Se usa para anular la identificación establecida en el catálogo de este video.

    Este campo no está validado.
    tags Matriz <Strings> si está presente, este token es válido solo para las etiquetas enumeradas autorizadas a reproducir.
    vids Matriz <Strings> Si está presente, este token solo autorizará la obtención de licencias para un conjunto de ID de video.
    cbeh Cuerda Establezca el valor en BLOCK_NEW para habilitar los límites de transmisión simultánea para bloquear cualquier solicitud nueva, incluso del mismo usuario, cuando se alcanza el número máximo de transmisiones.

    Establezca el valor en BLOCK_NEW_USER para bloquear cualquier solicitud nueva solo de un nuevo usuario cuando se alcanza el número máximo de transmisiones.

    El valor predeterminado bloquea la transmisión más antigua cuando se alcanza el número máximo de transmisiones.

    Límites de transmisión simultánea: Opcional
    cexp Cuerda Caducidad simultánea de la sesión: el valor predeterminado es 2 veces la duración del contenido o 15 minutos, lo que sea más largo.

    Esto define cuánto tiempo es válida la sesión, después del cual el espectador final tiene que iniciar una nueva sesión para continuar la reproducción. Ejemplo: 2h o 42m

    Límites de transmisión simultánea: Opcional
    climit Entero Cuando se incluye este campo, habilita los límites de transmisión simultánea junto con las solicitudes de renovación de licencia. Este valor indica la cantidad de observadores simultáneos permitidos.

    Límites de transmisión simultánea: Necesario
    dlimit Entero Cuando se incluye este campo, controla cuántos dispositivos se pueden asociar con el usuario especificado (uid). El valor debe ser> 0.

    Los dispositivos previamente permitidos seguirán funcionando si el dlimit el valor se elimina en solicitudes posteriores.

    Ejemplo: si el valor se establece en 3, el usuario puede jugar en los dispositivos A, B y C (todo estaría permitido). Intentar jugar en el dispositivo D sería denegado.

    Si el valor se cambia a 1 , el usuario aún puede jugar en los 3 dispositivos A, B y C, a menos que los dispositivos se revoquen manualmente mediante la administración de dispositivos con el API de dispositivos.

    Registro de dispositivo: Necesario
    sid Cuerda Especificar el ID de sesión de la transmisión actual le permite controlar cómo se define una sesión. De forma predeterminada, una sesión se define como User-Agent (navegador) + dirección IP + identificación de video.

    Por ejemplo, puede aflojar la definición de sesión a dirección IP + identificación de video.

    Límites de transmisión simultánea: Opcional
    uid Cuerda El ID de usuario del visor final. Este campo se utiliza para correlacionar varias sesiones para hacer cumplir los límites de transmisión simultánea.

    Registro de dispositivo: Necesario

    Genera un token

    Las bibliotecas están comúnmente disponibles para generar tokens JWT. Para obtener más detalles, consulte la Tokens web JSON sitio.

    Ejemplo de script de bash:

    Script de ejemplo para generar el token JWT:

    #! /usr/bin/env bash
    # Static header fields.
    HEADER='{
    	"type": "JWT",
    	"alg": "RS256"
    }'
    
    payload='{
    	"pkid": "{your_public_key_id}",
    	"accid": "{your_account_id}"
    }'
    
    # Use jq to set the dynamic `iat` and `exp`
    # fields on the payload using the current time.
    # `iat` is set to now, and `exp` is now + 1 second.
    PAYLOAD=$(
    	echo "${payload}" | jq --arg time_str "$(date +%s)" \
    	'
    	($time_str | tonumber) as $time_num
    	| .iat=$time_num
    	| .exp=($time_num + 60 * 60)
    	'
    )
    
    function b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }
    
    function rs_sign() { openssl dgst -binary -sha256 -sign playback-auth-keys/private.pem ; }
    
    JWT_HDR_B64="$(echo -n "$HEADER" | b64enc)"
    JWT_PAY_B64="$(echo -n "$PAYLOAD" | b64enc)"
    UNSIGNED_JWT="$JWT_HDR_B64.$JWT_PAY_B64"
    SIGNATURE=$(echo -n "$UNSIGNED_JWT" | rs_sign | b64enc)
    
    echo "$UNSIGNED_JWT.$SIGNATURE"
    

    Ejecute el script:

    $ bash jwtgen.sh
    

    Ejemplo usando Ir

    Aquí hay un ejemplo de una referencia. Ir implementación (como una herramienta cli) para generar tokens sin el uso de ninguna biblioteca de terceros:

    package main
    
    import (
    	"crypto"
    	"crypto/ecdsa"
    	"crypto/rand"
    	"crypto/rsa"
    	"crypto/sha256"
    	"crypto/x509"
    	"encoding/base64"
    	"encoding/json"
    	"encoding/pem"
    	"flag"
    	"fmt"
    	"io/ioutil"
    	"os"
    	"strings"
    	"time"
    )
    
    // Header is the base64UrlEncoded string of a JWT header for the RS256 algorithm
    const RSAHeader = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
    
    // Header is the base64UrlEncoded string of a JWT header for the EC256 algorithm
    const ECHeader = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9"
    
    // Claims represents constraints that should be applied to the use of the token
    type Claims struct {
    	Iat   float64 `json:"iat,omitempty"`   // Issued At
    	Exp   float64 `json:"exp,omitempty"`   // Expires At
    	Accid string  `json:"accid,omitempty"` // Account ID
    	Conid string  `json:"conid,omitempty"` // Content ID
    	Maxu  float64 `json:"maxu,omitempty"`  // Max Uses
    	Maxip float64 `json:"maxip,omitempty"` // Max IPs
    	Ua    string  `json:"ua,omitempty"`    // User Agent
    }
    
    func main() {
    	var key, algorithm string
    
    	c := Claims{Iat: float64(time.Now().Unix())}
    
    	flag.StringVar(&key, "key", "", "Path to private.pem key file")
    	flag.StringVar(&c.Accid, "account-id", "", "Account ID")
    	flag.StringVar(&c.Conid, "content-id", "", "Content ID (eg, video_id or live_job_id)")
    	flag.Float64Var(&c.Exp, "expires-at", float64(time.Now().AddDate(0, 0, 1).Unix()), "Epoch timestamp (in seconds) for when the token should stop working")
    	flag.Float64Var(&c.Maxu, "max-uses", 0, "Maximum number of times the token is valid for")
    	flag.Float64Var(&c.Maxip, "max-ips", 0, "Maximum number of unique IP addresses the token is valid for")
    	flag.StringVar(&c.Ua, "user-agent", "", "User Agent that the token is valid for")
    	flag.StringVar(&algorithm, "algo", "", "Key algorithm to use for signing. Valid: ec256, rsa256")
    	flag.Parse()
    
    	if key == "" {
    		fmt.Printf("missing required flag: -key\n\n")
    		flag.Usage()
    		os.Exit(1)
    	}
    
    	if algorithm == "" {
    		fmt.Printf("missing required flag: -algo\n\n")
    		flag.Usage()
    		os.Exit(2)
    	}
    
    	if algorithm != "rsa256" && algorithm != "ec256" {
    		fmt.Printf("missing valid value for -algo flag. Valid: rsa256, ec256\n\n")
    		flag.Usage()
    		os.Exit(3)
    	}
    
    	if c.Accid == "" {
    		fmt.Printf("missing required flag: -account-id\n\n")
    		flag.Usage()
    		os.Exit(4)
    	}
    
    	bs, err := json.Marshal(c)
    	if err != nil {
    		fmt.Println("failed to marshal token to json", err)
    		os.Exit(5)
    	}
    
    	kbs, err := ioutil.ReadFile(key)
    	if err != nil {
    		fmt.Println("failed to read private key", err)
    		os.Exit(6)
    	}
    
    	if algorithm == "rsa256" {
    		processRSA256(kbs, bs)
    	} else {
    		processEC256(kbs, bs)
    	}
    }
    
    func processRSA256(kbs, bs []byte) {
    	block, _ := pem.Decode(kbs)
    	if block == nil {
    		fmt.Println("failed to decode PEM block containing private key")
    		os.Exit(7)
    	}
    
    	if block.Type != "RSA PRIVATE KEY" {
    		fmt.Println("failed to decode PEM block containing private key")
    		os.Exit(8)
    	}
    
    	pKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    	if err != nil {
    		fmt.Println("failed to parse rsa private key", err)
    		os.Exit(9)
    	}
    
    	message := RSAHeader + "." + base64.RawURLEncoding.EncodeToString(bs)
    
    	hash := crypto.SHA256
    	hasher := hash.New()
    	_, _ = hasher.Write([]byte(message))
    	hashed := hasher.Sum(nil)
    
    	r, err := rsa.SignPKCS1v15(rand.Reader, pKey, hash, hashed)
    	if err != nil {
    		fmt.Println("failed to sign token", err)
    		os.Exit(10)
    	}
    
    	sig := strings.TrimRight(base64.RawURLEncoding.EncodeToString(r), "=")
    
    	fmt.Println(message + "." + sig)
    }
    
    func processEC256(kbs, bs []byte) {
    	block, _ := pem.Decode(kbs)
    	if block == nil {
    		fmt.Println("failed to decode PEM block containing private key")
    		os.Exit(7)
    	}
    
    	if block.Type != "EC PRIVATE KEY" {
    		fmt.Println("failed to decode PEM block containing private key")
    		os.Exit(8)
    	}
    
    	pkey, err := x509.ParseECPrivateKey(block.Bytes)
    	if err != nil {
    		fmt.Println("failed to parse ec private key", err)
    		os.Exit(9)
    	}
    
    	message := ECHeader + "." + base64.RawURLEncoding.EncodeToString(bs)
    	hash := sha256.Sum256([]byte(message))
    
    	r, s, err := ecdsa.Sign(rand.Reader, pkey, hash[:])
    	if err != nil {
    		fmt.Println("failed to sign token", err)
    		os.Exit(10)
    	}
    
    	curveBits := pkey.Curve.Params().BitSize
    
    	keyBytes := curveBits / 8
    	if curveBits%8 > 0 {
    		keyBytes++
    	}
    
    	rBytes := r.Bytes()
    	rBytesPadded := make([]byte, keyBytes)
    	copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
    
    	sBytes := s.Bytes()
    	sBytesPadded := make([]byte, keyBytes)
    	copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
    
    	out := append(rBytesPadded, sBytesPadded...)
    
    	sig := base64.RawURLEncoding.EncodeToString(out)
    	fmt.Println(message + "." + sig)
    }
    

    Resultados

    Aquí hay un ejemplo de un token decodificado usando https://JWT.io especificando el conjunto completo de reclamaciones:

    ENCABEZAMIENTO:

    {
      "alg": "RS256",
      "type": "JWT"
    }
    

    CARGA ÚTIL:

    {
      "accid": "1100863500123",
      "conid": "51141412620123",
      "exp": 1554200832,
      "iat": 1554199032,
      "maxip": 10,
      "maxu": 10,
      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
    }
    

    Prueba de reproducción

    Aunque no es obligatorio, es posible que desee probar la reproducción de video antes de configurar un reproductor.

    Solicitar reproducción:

    curl -X GET \
     -H 'Authorization: Bearer {JWT}' \
     https://edge-auth.api.brightcove.com/playback/v1/accounts/{your_account_id}/videos/{your_video_id}
    

    Página actualizada por última vez el 27 Jan 2022