Einführung
Um beim Zugriff auf Ihre Videobibliothek eine zusätzliche Schutzstufe hinzuzufügen oder Einschränkungen auf Benutzerebene für Ihre Inhalte anzuwenden, können Sie eine JSON-Webtoken (JWT) mit Ihrem Aufruf an die Brightcove Playback API. Gehen Sie folgendermaßen vor, um das Token zu erstellen:
Generieren Sie ein öffentlich-privates Schlüsselpaar
Der Herausgeber generiert ein öffentlich-privates Schlüsselpaar und stellt Brightcove den öffentlichen Schlüssel bereit. Der private Schlüssel wird vom Herausgeber zum Signieren von Token verwendet und nicht mit Brightcove geteilt.
Es gibt viele Möglichkeiten, das öffentlich-private Schlüsselpaar zu generieren. Hier sind einige Beispiele:
Beispiel für ein 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 Programmiersprache Go, um das Schlüsselpaar zu generieren:
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");
Öffentlichen Schlüssel registrieren
Sie verwenden die Schlüssel-API, um Ihren öffentlichen Schlüssel bei Brightcove zu registrieren.
Schlüssel-API
Die Schlüssel-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
Kontopfad
In allen Fällen werden Anfragen für ein bestimmtes Video Cloud-Konto gestellt. Sie fügen also immer den Begriff Konten gefolgt von Ihrer Konto-ID zur Basis-URL hinzu:
https://playback-auth.api.brightcove.com/v1/accounts/{accountID}
Genehmigung
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-Dienst abgerufen werden muss. Ausführliche Informationen zum Abrufen von Client-Anmeldeinformationen und deren Verwendung zum Abrufen von Zugriffstoken finden Sie im Übersicht über Brightcove OAuth.
Berechtigungen
Anfragen an die Schlüssel-API müssen gestellt werden von Kundenanmeldeinformationen mit folgenden Berechtigungen:
-
video-cloud/playback-auth/key/read -
video-cloud/playback-auth/key/write
Schlüssel verwalten
Die Key API unterstützt die folgenden Anfragen:
Registrieren Sie einen neuen Schlüssel:
Geben Sie den Wert Ihres öffentlichen Schlüssels in den API-Anfragetext ein. Den Schlüssel findest du im public_key.txt Datei.
Anfrage
POST /v1/accounts/{accountID}/keys
Content-Type: application/json
Body: {"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj...MyeQviqploA=="}
Verwendung von Curl
curl -X POST \\ -H "Content-Type: application/json" \\ -H "Autorisierung: Träger {access_token} " \\ -D '{"value": "{your_public_key_value}"}' \\ https://playback-auth.api.brightcove.com/v1/accounts/{accountID}/Schlüssel
Antwort
{
"id": "{your_public_key_id}",
"type": "public",
"algorithm": "rsa",
"value": "{your_public_key_value}",
"createdAt": "2020-01-03T20:30:36.488Z"
}
Listenschlüssel:
Rufen Sie eine Liste der öffentlichen Schlüssel in Ihrem Konto ab.
GET /v1/accounts/{accountID}/keys
Holen Sie sich einen Schlüssel:
Rufen Sie die Details für einen öffentlichen Schlüssel in Ihrem Konto ab.
GET /v1/accounts/{accountID}/keys/{key_Id}
Einen Schlüssel löschen:
Löschen Sie einen öffentlichen Schlüssel in Ihrem Konto.
DELETE /v1/accounts/{accountID}/keys/{key_Id}
Ein ... kreieren JSON-Webtoken
Publisher erstellen a JSON-Webtoken (JWT). Das Token wird mit dem RSA-Algorithmus unter Verwendung des SHA-256-Hash-Algorithmus signiert (in der JWT-Spezifikation als "RS256") Es werden keine anderen JWT-Algorithmen unterstützt.
Eine Teilmenge des Standards JSON-Webtoken-Ansprüche verwendet werden, zusammen mit einigen von Brightcove definierten privaten Ansprüchen. Sie erstellen eine JSON-Webtoken mit Ihrem privaten Schlüssel signiert.
Ansprüche auf statische URL-Zustellung
Eine Liste der Ansprüche, die verwendet werden können, finden Sie im Statische URL-Zustellung dokumentieren.
Ansprüche auf Wiedergabeautorisierung
Die folgenden Ansprüche können verwendet werden mit Der Wiedergabeautorisierungsdienst von Brightcove.
| Gebiet | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
accid |
Zeichenfolge | Jawohl | Die Konto-ID, die den wiedergegebenen Inhalt besitzt |
exp |
Ganze Zahl | Jawohl | Zeit, in der dieser Token nicht mehr gültig ist, in Sekunden seit der Epoche. Darf nicht länger als 30 Tage von sein iat |
iat |
Ganze Zahl | Jawohl | Zeit, zu der dieser Token ausgegeben wurde, in Sekunden seit der Epoche |
conid |
Zeichenfolge | Falls vorhanden, autorisiert dieses Token nur den Lizenzabruf für eine bestimmte Video Cloud-Video-ID.
Muss eine gültige Video-ID sein. |
|
maxip |
Ganze Zahl | Falls vorhanden, kann dieses Token nur von so vielen verschiedenen IP-Adressen verwendet werden. (DRM & AES-128)
Erforderlich für die Sitzungsverfolgung. |
|
maxu |
Ganze Zahl |
Falls vorhanden, ist dieses Token nur für so viele Lizenzanforderungen gültig. (DRM & AES-128)
|
|
ua |
Zeichenfolge | Falls vorhanden, ist dieses Token nur für Anfragen von diesem User-Agent gültig.
Dieses Feld ist nicht validiert. |
Ansprüche auf Wiedergaberechte
Die folgenden Ansprüche können verwendet werden mit Der Wiedergaberechte-Verwaltungsdienst von Brightcove.
| Gebiet | Typ | Erforderlich | Erforderlich für gleichzeitige Stream-Limits | Nur DRM | Beschreibung |
|---|---|---|---|---|---|
accid |
Zeichenfolge | Jawohl | Die Konto-ID, die den wiedergegebenen Inhalt besitzt | ||
exp |
Ganze Zahl | Jawohl | Zeit, in der dieser Token nicht mehr gültig ist, in Sekunden seit der Epoche. Darf nicht länger als 30 Tage von sein iat |
||
iat |
Ganze Zahl | Jawohl | Zeit, zu der dieser Token ausgegeben wurde, in Sekunden seit der Epoche | ||
nbf |
Ganze Zahl | Zeit, zu der dieser Token gültig wird, in Sekunden seit der Epoche | |||
pkid |
Zeichenfolge | Die öffentliche Schlüssel-ID, die zum Verifizieren dieses Tokens verwendet wird. Es ist beim Playback Authorization Service von Brightcove registriert und muss das RSA-Schlüsselformat verwenden.
Wenn pkid angegeben ist, validieren wir das Token mit dem angegebenen Schlüssel.
Wenn nein pkid angegeben ist, rufen wir alle Schlüssel für das Konto ab und versuchen, sie gegen alle zu validieren.
|
|||
prid |
Zeichenfolge | 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 <Strings> | falls vorhanden, ist dieses Token nur für die aufgelisteten Tags gültig, die zur Wiedergabe berechtigt sind. | |||
vids |
Array <Strings> | Falls vorhanden, autorisiert dieses Token nur den Lizenzabruf für eine Reihe von Video-IDs. | |||
cbeh |
Zeichenfolge | Jawohl | Setzen Sie den Wert auf BLOCK_NEW um gleichzeitige Stream-Limits zu aktivieren, um jede neue Anfrage zu blockieren, auch von demselben Benutzer, wenn die maximale Anzahl von Streams erreicht ist.
Setzen Sie den Wert auf BLOCK_NEW_USER um jede neue Anfrage nur von einem neuen Benutzer zu blockieren, wenn die maximale Anzahl von Streams erreicht ist.
Standardmäßig wird der älteste Stream blockiert, wenn die maximale Anzahl von Streams erreicht ist. Limits für gleichzeitige Streams: Optional |
||
cexp |
Zeichenfolge | Jawohl | Gleichzeitigkeitsablauf der Sitzung – Standardmäßig ist die Dauer des Inhalts doppelt so hoch oder 15 Minuten, je nachdem, was länger ist.
Dies legt fest, wie lange die Sitzung gültig ist, nach welcher Zeit der Endbetrachter eine neue Sitzung starten muss, um die Wiedergabe fortzusetzen. Beispiel: 2h oder 42m
Limits für gleichzeitige Streams: Optional |
||
climit |
Ganze Zahl | Jawohl | Jawohl | Wenn dieses Feld eingeschlossen ist, ermöglicht es gleichzeitige Stream-Limits zusammen mit Lizenzverlängerungsanforderungen. Dieser Wert gibt die zulässige Anzahl gleichzeitiger Watcher an.
Limits für gleichzeitige Streams: Erforderlich |
|
dlimit |
Ganze Zahl | Jawohl | Wenn dieses Feld enthalten ist, steuert es, wie viele Geräte dem angegebenen Benutzer zugeordnet werden können (uid). Wert muss > . sein 0.
Zuvor zugelassene Geräte funktionieren weiterhin, wenn die dlimit Wert wird in späteren Anforderungen gelöscht.
Beispiel: wenn der Wert auf gesetzt 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, wird abgelehnt.
Wenn der Wert auf 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 die Geräte mit dem verwaltet werden Geräte-API.
Geräteregistrierung: Erforderlich |
||
sid |
Zeichenfolge | Jawohl | Durch die Angabe der Sitzungs-ID des aktuellen Streams können Sie steuern, wie eine Sitzung definiert wird. Standardmäßig ist eine Sitzung als User-Agent (Browser) + IP-Adresse + Video-ID definiert.
Sie können beispielsweise die Definition der Sitzung auf IP-Adresse + Video-ID lockern. Limits für gleichzeitige Streams: Optional |
||
uid |
Zeichenfolge | Jawohl | Die Benutzer-ID des End-Viewers. Dieses Feld wird verwendet, um mehrere Sitzungen zu korrelieren, um gleichzeitige Stream-Limits zu erzwingen.
Geräteregistrierung: Erforderlich |
Token generieren
Bibliotheken sind allgemein verfügbar, um JWT-Token zu generieren. Einzelheiten finden Sie im JSON-Webtoken Seite? ˅.
Beispiel für ein Bash-Skript:
Beispielskript zum Generieren des JWT-Tokens:
#! /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 Referenz-Go-Implementierung (als CLI-Tool) zum Generieren von Token ohne die Verwendung einer Drittanbieterbibliothek:
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 Angabe des vollständigen Anspruchssatzes:
HEADER:
{
"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"
}
Wiedergabe testen
Obwohl dies nicht erforderlich ist, sollten Sie die Videowiedergabe testen, bevor Sie einen Player konfigurieren.
Wiedergabe anfordern:
curl -X GET \
-H 'Authorization: Bearer {JWT}' \
https://edge-auth.api.brightcove.com/playback/v1/accounts/{your_account_id}/videos/{your_video_id}