Einführung
Um einen zusätzlichen Schutz beim Zugriff auf Ihre Videothek hinzuzufügen oder Einschränkungen auf Benutzerebene für Ihre Inhalte anzuwenden, können Sie mit Ihrem Aufruf eine JSON Web Token (JWT) an die Brightcove Playback-API weiterleiten. Gehen Sie folgendermaßen vor, um das Token zu erstellen:
Generieren eines öffentlich-privaten Schlüsselpaars
Der Publisher generiert ein öffentlich-privates Schlüsselpaar und stellt Brightcove den öffentlichen Schlüssel zur Verfügung. Der private Schlüssel wird vom Publisher verwendet, um Token zu signieren, und wird nicht mit Brightcove geteilt.
Es gibt viele Möglichkeiten, das öffentlich-private Schlüsselpaar zu generieren. Hier sind ein paar Beispiele:
Beispiel Bash-Skript:
Beispielskript zum Generieren des Schlüsselpaars:
#!/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"
Führen Sie das Skript aus:
$ bash keygen.sh
Beispiel mit Go
Beispiel mit der Go Programmiersprache zum Generieren des Schlüsselpaars:
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)
}
Beispiel mit node.js
Beispiel mit node.js zum Generieren des Schlüsselpaars:
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");
Registrieren öffentlicher Schlüssel
Sie werden die Key-API verwenden, um Ihren öffentlichen Schlüssel bei Brightcove zu registrieren.
Schlüssel-API
Die Key-API wird verwendet, um Ihre öffentlichen Schlüssel mit Brightcove zu verwalten.
Basis-URL
Die Basis-URL für die API lautet:
https://playback-auth.api.brightcove.com
Konto-Pfad
In allen Fällen werden Anfragen für ein bestimmtes Video Cloud-Konto gestellt. Daher fügen Sie immer den Begriff Konten gefolgt von Ihrer Konto-ID zur Basis-URL hinzu:
https://playback-auth.api.brightcove.com/v1/accounts/{accountID}
Autorisierung
Ein Zugriffstoken für Anfragen ist erforderlich und muss im Authorization-Header vorhanden sein:
Authorization: Bearer {access_token}
Das Zugriffstoken ist ein temporäres OAuth2-Zugriffstoken, das vom Brightcove OAuth Service bezogen werden muss. Weitere Informationen zum Abrufen von Client-Anmeldeinformationen und zum Abrufen von Zugriffstoken finden Sie in der Brightcove OAuth Overview.
Berechtigungen
Anfragen an die Schlüssel-API müssen von Client-Anmeldeinformationen mit den folgenden Berechtigungen gestellt werden:
-
video-cloud/playback-auth/key/read
-
video-cloud/playback-auth/key/write
Schlüssel verwalten
Die Key-API unterstützt die folgenden Anfragen:
Registriere einen neuen Schlüssel:
Geben Sie den Wert Ihres öffentlichen Schlüssels in den API-Anforderungskörper ein. Sie finden den Schlüssel in der Datei public_key.txt .
Anforderung
POST /v1/accounts/{accountID}/keys
Content-Type: application/json
Body: {"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj...MyeQviqploA=="}
Verwenden von Curl
REAKTION
{
"id": "{your_public_key_id}",
"type": "public",
"algorithm": "rsa",
"value": "{your_public_key_value}",
"createdAt": "2020-01-03T20:30:36.488Z"
}
Schlüssel auflisten:
Holen Sie sich eine Liste mit öffentlichen Schlüsseln in Ihrem Konto.
GET /v1/accounts/{accountID}/keys
Holen Sie sich einen Schlüssel:
Holen Sie sich die Details für einen öffentlichen Schlüssel in Ihrem Konto.
GET /v1/accounts/{accountID}/keys/{key_Id}
Löschen Sie einen Schlüssel:
Löschen Sie einen öffentlichen Schlüssel in Ihrem Konto.
DELETE /v1/accounts/{accountID}/keys/{key_Id}
Erstellen Sie ein JSON Web Token
Verlage erstellen ein JSON Web Token (JWT). Das Token ist mit dem RSA-Algorithmus unter Verwendung des SHA-256-Hash-Algorithmus signiert (in der JWT-Spezifikation als "RS256„identifiziert) Es werden keine anderen JWT-Algorithmen unterstützt.
Eine Teilmenge des Standards JSON Web Token claims wird zusammen mit einigen privaten Ansprüchen verwendet, die von Brightcove definiert wurden. Sie erstellen einen mit Ihrem privaten Schlüssel JSON Web Token signierten Schlüssel.
Ansprüche wegen statischer URL-Lieferung
Die folgenden Ansprüche können mit der statischen URL-Lieferung von Brightcove verwendet werden.
Feld | Art | Erforderlich | Beschreibung |
---|---|---|---|
accid |
String | Die Konto-ID, der der abgespielte Inhalt gehört | |
drules |
String[] | Eine Liste der anzuwendenden Aktions-IDs für Bereitstellungsregeln, siehe Implementierungsregeln für Lieferregeln . Wenn der Abfrageparameter config_id ebenfalls festgelegt ist, wird er ignoriert, da dieser Anspruch ihn außer Kraft setzt. | |
exp |
Ganzzahl | Zeit, in der dieses Token nicht mehr gültig ist, in Sekunden seit der Epoche. Muss nicht mehr als 30 Tage ab iat |
|
iat |
Ganzzahl | Zeit, zu der dieses Token ausgegeben wurde, in Sekunden seit der Epoche | |
conid |
String | Falls vorhanden, autorisiert dieses Token nur das Abrufen von Lizenzen für eine bestimmte Video Cloud-Video-ID. Muss eine gültige Video-ID sein. |
|
pro |
String | Gibt einen Schutztyp für den Fall an, dass mehrere für ein einzelnes Video verfügbar sind. Werte:
|
|
vod |
Objekt | Enthält spezifische Konfigurationsoptionen für Video-On-Demand. | |
ssai |
String | Ihre serverseitige Ad Insertion (SSAI) -Konfigurations-ID. Dieser Anspruch ist erforderlich , um entweder einen HLS oder einen DASH VMAP abzurufen. |
Hier ist ein Beispiel für die JSON Web Token (JWT) Ansprüche, die Sie möglicherweise verwenden:
{
// 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"
}
}
Ansprüche auf Wiedergabe-Autorisierung
Die folgenden Ansprüche können mit dem Playback-Autorisierungsdienst von Brightcoveverwendet werden.
Feld | Art | Erforderlich | Beschreibung |
---|---|---|---|
accid |
String | Ja | Die Konto-ID, der der abgespielte Inhalt gehört |
exp |
Ganzzahl | Ja | Zeit, in der dieses Token nicht mehr gültig ist, in Sekunden seit der Epoche. Muss nicht mehr als 30 Tage ab iat |
iat |
Ganzzahl | Ja | Zeit, zu der dieses Token ausgegeben wurde, in Sekunden seit der Epoche |
ua |
String | Falls vorhanden, ist dieses Token nur für Anfragen von diesem User-Agent gültig. Dieses Feld ist nicht validiert. |
|
conid |
String | Falls vorhanden, autorisiert dieses Token nur das Abrufen von Lizenzen für eine bestimmte Video Cloud-Video-ID. Muss eine gültige Video-ID sein. |
|
maxip |
Ganzzahl | Falls vorhanden, kann dieses Token nur von diesen vielen verschiedenen IP-Adressen verwendet werden. (DRM & AES-128) Erforderlich für das Session Tracking. |
|
maxu |
Ganzzahl |
Falls vorhanden, gilt dieses Token nur für so viele Lizenzanfragen. (DRM & AES-128)
|
Ansprüche auf Wiedergaberechte
Die folgenden Ansprüche können mit dem Playback Rights Management Service von Brightcoveverwendet werden.
Feld | Art | Erforderlich | Erforderlich für Parallel | nur DRM | Beschreibung |
---|---|---|---|---|---|
accid |
String | Ja | Die Konto-ID, der der abgespielte Inhalt gehört | ||
exp |
Ganzzahl | Ja | Zeit, in der dieses Token nicht mehr gültig ist, in Sekunden seit der Epoche. Muss nicht mehr als 30 Tage ab iat |
||
iat |
Ganzzahl | Ja | Zeit, zu der dieses Token ausgegeben wurde, in Sekunden seit der Epoche | ||
pkid |
String | Ja | Die ID des öffentlichen Schlüssels, mit der dieses Token überprüft wird. Der beim Playback-Autorisierungsdienst von Brightcove registrierte öffentliche Schlüssel muss das RSA-Schlüsselformat verwenden. Zuvor erstellte EC-Schlüssel funktionieren nicht. Dieses Feld ist nicht validiert. |
||
nbf |
Ganzzahl | Zeit, zu der dieser Token in Sekunden seit der Epoche gültig ist | |||
prid |
String | EIN playback_rights_id . Wird verwendet, um die im Katalog für dieses Video festgelegte ID zu überschreiben Dieses Feld ist nicht validiert. |
|||
tags |
<Array-Zeichen> | falls vorhanden, gilt dieses Token nur für die aufgelisteten Tags, die zur Wiedergabe autorisiert sind. | |||
offers |
<Array-Zeichen> | falls vorhanden, gilt dieses Token nur für die aufgelisteten Angebote, die zur Wiedergabe autorisiert sind. | |||
vids |
<Array-Zeichen> | Falls vorhanden, autorisiert dieses Token nur das Abrufen von Lizenzen für eine Reihe von Video-IDs. | |||
uid |
String | Ja | Ja | Die Benutzer-ID des Endbetrachters. Dieses Feld wird verwendet, um mehrere Sitzungen zu korrelieren, um Stream-Concurrency durchzusetzen. Erforderlich für die Registrierung von Geräten |
|
sid |
String | Ja | Die Angabe der Sitzungs-ID des aktuellen Streams ermöglicht eine benutzerdefinierte Kontrolle darüber, was eine Sitzung definiert. Wenn nicht angegeben, ist der Standardwert eine Kombination aus User-Agent, IP-Adresse und Video-ID. Erforderlich für die Parallelität der |
||
cexp |
String | Ja | Parallelität Ablauf der Sitzung - Der Standardwert ist das Zweifache der Dauer des Inhalts. Dies definiert, wie lange die Sitzung gültig ist. Danach muss der Endbetrachter eine neue Sitzung starten, um die Wiedergabe fortzusetzen. Beispiel: 2h oder 42m Erforderlich für die Gleichzeitig/Sitzung. |
||
climit |
Ganzzahl | Ja | Ja | Wenn dieses Feld enthalten ist, wird die Überprüfung von Stream Concurrency zusammen mit Anfragen zur Lizenzverlängerung aktiviert. Dieser Wert gibt die Anzahl der zulässigen gleichzeitigen Beobachter an. Erforderlich für die Parallelität der |
|
dlimit |
Ganzzahl | Ja | Wenn dieses Feld enthalten ist, steuert es, wie viele Geräte dem angegebenen Benutzer zugeordnet werden können (uid ). Der Wert muss sein > 0 . Zuvor zugelassene Geräte funktionieren weiterhin, wenn der dlimit Wert in späteren Anfragen fallen gelassen wird. Beispiel: Wenn der Wert auf festgelegt ist 3 , kann der Benutzer auf den Geräten A, B und C spielen (alles wäre erlaubt). Der Versuch, auf Gerät D zu spielen, würde abgelehnt werden. Wenn der Wert geändert wird 1 , kann der Benutzer weiterhin auf allen 3 Geräten A, B und C spielen, es sei denn, die Geräte werden manuell widerrufen, indem Geräte mit der Playback Rights APIverwaltet werden. Erforderlich für die Registrierung von Geräten |
Generieren Sie ein Token
Bibliotheken sind allgemein verfügbar, um JWT-Token zu generieren. Einzelheiten finden Sie auf der JSON Web Tokens Website.
Beispiel Bash-Skript:
Beispielskript zum Generieren des JWT-Token:
#! /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"
Führen Sie das Skript aus:
$ bash jwtgen.sh
Beispiel mit Go
Hier ist ein Beispiel für eine Go Referenzimplementierung (als CLI-Tool) zum Generieren von Token ohne Verwendung einer Bibliothek von Drittanbietern:
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)
}
Ergebnisse
Hier ist ein Beispiel für ein dekodiertes Token mit https://JWT.io , das den vollständigen Satz von Ansprüchen angibt:
ÜBERSCHRIFT:
{
"alg": "RS256",
"type": "JWT"
}
NUTZLAST:
{
"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"
}
Test-Wiedergabe
Obwohl dies nicht erforderlich ist, möchten Sie möglicherweise die Videowiedergabe testen, bevor Sie einen Player konfigurieren.
Wiedergabe anfragen:
curl -X GET \
-H 'Authorization: Bearer {JWT}' \
https://edge-auth.api.brightcove.com/playback/v1/accounts/{your_account_id}/videos/{your_video_id}