soporte Contactar con Soporte | Estadoestado del sistema del sistema
Contenido de la página

    Creación de un token web JSON (JWT)

    En este tema, aprenderá cómo crear un JSON Web Token (JWT) que se puede utilizar al comunicarse con la API de reproducción de Brightcove.

    Introducción

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

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

    Generar par de claves público-privadas

    El editor generará un par de claves público-privadas 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 maneras de generar el par de claves público-privadas. Aquí hay algunos ejemplos:

    Ejemplo de script bash:

    Ejemplo de secuencia de comandos 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 Go

    Ejemplo usando el lenguaje de Go 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 de uso de 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 para la API es:

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

    Ruta de la cuenta

    En todos los casos, se solicitarán una cuenta de Video Cloud específica. Por lo tanto, siempre agregará las cuentas de término seguidas de su ID de cuenta a la URL base:

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

    Autorización

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

    Authorization: Bearer {access_token}

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

    Permisos

    Las solicitudes a la API de clave deben realizarse desde credenciales de 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:

    Registrar una nueva clave:

    Coloque el valor de su clave pública en el cuerpo de la solicitud de API. Puede encontrar la clave en el archivo public_key.txt.

    Solicitud
    POST /v1/accounts/{accountID}/keys
        Content-Type: application/json
        Body: {"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj...MyeQviqploA=="}
    
    Uso de 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"
    }

    Claves de lista:

    Obtén una lista de claves públicas en tu cuenta.

    GET /v1/accounts/{accountID}/keys

    Obtener una clave:

    Obtén los detalles de una clave pública en tu 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 JSON Web Token

    Los editores crean un (JWT).JSON Web Token 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.

    Se JSON Web Token claims utilizará un subconjunto del estándar, junto con algunas afirmaciones privadas definidas por Brightcove. Creará un firmado con su clave privada.JSON Web Token

    Reclamaciones de entrega de URL estática

    Las siguientes afirmaciones se pueden utilizar con la Entrega de URL estática de Brightcove.

    Campo Tipo Obligatorio Descripción
    accid Cadena El ID de cuenta que posee el contenido que se está reproduciendo
    drules Cadena [] Lista de identificadores de acciones de regla de entrega que se deben aplicar, consulte Implementación de reglas de entrega para obtener más detalles Si también se establece el parámetro de consulta config_id, se ignorará, ya que esta afirmación lo anula.
    exp Entero Tiempo que este token ya no será válido, en segundos desde la Época. No debe ser superior a 30 días desdeiat
    iat Entero Tiempo en que se emitió este token, en segundos desde la Época
    conid Cadena Si está presente, este token sólo autorizará la obtención de licencias para un identificador de vídeo de Video Cloud específico.

    Debe ser un ID de vídeo válido.
    pro Cadena Especifica un tipo de protección en el caso en que haya varios disponibles para un solo vídeo.

    Valores:
    • «» (valor predeterminado para el contenido claro)
    • «aes128"
    • «widevine»
    • «playready»
    • «Fairplay»
    vod Objeto Contiene opciones de configuración específicas para Vídeo bajo demanda.
    ssai Cadena Su ID de configuración de inserción de anuncios en el lado del servidor (SSAI). Esta afirmación es necesaria para recuperar un HLS o un VMAP de DASH.

    Aquí hay un ejemplo de las afirmaciones JSON Web Token (JWT) que podría usar:

    {
    // account id: JWT is only valid for this accounts
    "accid":"4590388311111",
    // drules: list of delivery rule IDs to be applied
    "drules": ["0758da1f-e913-4f30-a587-181db8b1e4eb"]
    // expires: timestamp when JWT expires
    "exp":1577989732,
    // issued at: timestamp when the JWT was created
    "iat":1575484132,
    // content id: JWT is only valid for video id or reference id
    "conid":"5805807122222",
    // protection: specify a protection type in the case where multiple are available for a single video
    "pro":"aes128",
    // VOD specific configuration options
    "vod":{
    // SSAI configuration to apply
    "ssai":"efcc566-b44b-5a77-a0e2-d33333333333"
    }
    }

    Generar un token

    Las bibliotecas suelen estar disponibles para generar tokens JWT. Para obtener más información, consulte el JSON Web Tokens sitio.

    Ejemplo de script bash:

    Ejemplo de secuencia de comandos 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 Go

    Aquí hay un ejemplo de una Go implementación de referencia (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:

    ENCABEZADO:

    {
      "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"
    }
    

    Probar la reproducción

    Aunque no es necesario, es posible que desee probar la reproducción de vídeo 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}