ストリームを保護する
デフォルトでは、Stream上の動画は動画IDを持っている誰でも視聴できます。動画をデフォルトでプライベートにし、特定のユーザーにのみアクセスを許可したい場合は、サイン付きURL機能を使用できます。動画をサイン付きURLを必要とするようにマークすると、動画IDだけでは公開アクセスできなくなります。代わりに、ユーザーは動画を視聴またはダウンロードするためにサイン付きURLトークンが必要になります。
サイン付きURLを使用する一般的なユースケースは以下の通りです:
- ログインしたメンバーのみが特定の動画を視聴できるように制限する
- ユーザーが動画を限られた時間(例:24時間)視聴できるようにする
- 地理的位置に基づいてアクセスを制限する
動画IDはサイン付きURL内で実質的に公開されているため、動画に対してrequireSignedURLsをオンにする必要があります。このオプションを有効にすると、watch.cloudflarestream.com/{video_uid}のような公開リンクが機能しなくなります。
視聴制限は動画のメタデータを更新することで行えます。
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/{video_uid}" \--header "Authorization: Bearer <API_TOKEN>" \--header "Content-Type: application/json" \--data "{\"uid\": \"<VIDEO_UID>\", \"requireSignedURLs\": true }"レスポンス:
{ "result": { "uid": "<VIDEO_UID>", ... "requireSignedURLs": true }, "success": true, "errors": [], "messages": []}アプリをプログラムしてトークンを生成する方法は2つあります:
-
/tokenエンドポイントを使用してサイン付きトークンを生成する: サイン付きURLトークンを作成する最も簡単な方法は、/tokenエンドポイントを呼び出すことです。これはテスト目的や、1日あたり10,000トークン未満を生成する場合に推奨されます。
-
オープンソースライブラリを使用する: 毎日数万のユーザーがいて、/tokenエンドポイントを毎回呼び出さずに大量のトークンを生成する必要がある場合は、自分でトークンを作成できます。この方法では、トークンを生成するたびにStreamエンドポイントを呼び出す必要がありません。
プライベートにマークされた任意の動画に対して/tokenエンドポイントを呼び出すことで、1時間で期限切れになるサイン付きURLトークンを取得できます:
curl --request POST \https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/{video_uid}/token \--header "Authorization: Bearer <API_TOKEN>"リクエストが成功すると、次のようなレスポンスが表示されます:
{ "result": { "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNkYzkzNTk4MmY4MDc1ZjJlZjk2MTA2ZDg1ZmNkODM4In0.eyJraWQiOiJjZGM5MzU5ODJmODA3NWYyZWY5NjEwNmQ4NWZjZDgzOCIsImV4cCI6IjE2MjE4ODk2NTciLCJuYmYiOiIxNjIxODgyNDU3In0.iHGMvwOh2-SuqUG7kp2GeLXyKvMavP-I2rYCni9odNwms7imW429bM2tKs3G9INms8gSc7fzm8hNEYWOhGHWRBaaCs3U9H4DRWaFOvn0sJWLBitGuF_YaZM5O6fqJPTAwhgFKdikyk9zVzHrIJ0PfBL0NsTgwDxLkJjEAEULQJpiQU1DNm0w5ctasdbw77YtDwdZ01g924Dm6jIsWolW0Ic0AevCLyVdg501Ki9hSF7kYST0egcll47jmoMMni7ujQCJI1XEAOas32DdjnMvU8vXrYbaHk1m1oXlm319rDYghOHed9kr293KM7ivtZNlhYceSzOpyAmqNFS7mearyQ" }, "success": true, "errors": [], "messages": []}動画を表示するには、tokenの値をvideo idの代わりに挿入します:
<iframe src="https://customer-<CODE>.cloudflarestream.com/eyJhbGciOiJSUzI1NiIsImtpZCI6ImNkYzkzNTk4MmY4MDc1ZjJlZjk2MTA2ZDg1ZmNkODM4In0.eyJraWQiOiJjZGM5MzU5ODJmODA3NWYyZWY5NjEwNmQ4NWZjZDgzOCIsImV4cCI6IjE2MjE4ODk2NTciLCJuYmYiOiIxNjIxODgyNDU3In0.iHGMvwOh2-SuqUG7kp2GeLXyKvMavP-I2rYCni9odNwms7imW429bM2tKs3G9INms8gSc7fzm8hNEYWOhGHWRBaaCs3U9H4DRWaFOvn0sJWLBitGuF_YaZM5O6fqJPTAwhgFKdikyk9zVzHrIJ0PfBL0NsTgwDxLkJjEAEULQJpiQU1DNm0w5ctasdbw77YtDwdZ01g924Dm6jIsWolW0Ic0AevCLyVdg501Ki9hSF7kYST0egcll47jmoMMni7ujQCJI1XEAOas32DdjnMvU8vXrYbaHk1m1oXlm319rDYghOHed9kr293KM7ivtZNlhYceSzOpyAmqNFS7mearyQ/iframe" style="border: none;" height="720" width="1280" allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;" allowfullscreen="true"></iframe>独自のプレーヤーを使用している場合は、マニフェストURL内の動画IDをtokenの値に置き換えます:
https://customer-<CODE>.cloudflarestream.com/eyJhbGciOiJSUzI1NiIsImtpZCI6ImNkYzkzNTk4MmY4MDc1ZjJlZjk2MTA2ZDg1ZmNkODM4In0.eyJraWQiOiJjZGM5MzU5ODJmODA3NWYyZWY5NjEwNmQ4NWZjZDgzOCIsImV4cCI6IjE2MjE4ODk2NTciLCJuYmYiOiIxNjIxODgyNDU3In0.iHGMvwOh2-SuqUG7kp2GeLXyKvMavP-I2rYCni9odNwms7imW429bM2tKs3G9INms8gSc7fzm8hNEYWOhGHWRBaaCs3U9H4DRWaFOvn0sJWLBitGuF_YaZM5O6fqJPTAwhgFKdikyk9zVzHrIJ0PfBL0NsTgwDxLkJjEAEULQJpiQU1DNm0w5ctasdbw77YtDwdZ01g924Dm6jIsWolW0Ic0AevCLyVdg501Ki9hSF7kYST0egcll47jmoMMni7ujQCJI1XEAOas32DdjnMvU8vXrYbaHk1m1oXlm319rDYghOHed9kr293KM7ivtZNlhYceSzOpyAmqNFS7mearyQ/manifest/video.m3u8
ボディなしで/tokenエンドポイントを呼び出すと、1時間で期限切れになるトークンが返されます。特定の動画を次の12時間視聴できるようにしたい場合は、Cloudflare Workerを使用して次のように行います:
addEventListener('fetch', event => { event.respondWith(handleRequest(event))})
async function handleRequest(request) {
var signed_url_restrictions = { //次の12時間視聴を制限 exp: Math.floor(Date.now() / 1000) + (12*60*60) };
const init = { method: 'POST', headers: { "Authorization": "Bearer <API_TOKEN>", "content-type": "application/json;charset=UTF-8" }, body: JSON.stringify(signed_url_restrictions) } const signedurl_service_response = await fetch("https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/{video_uid}/token", init) return new Response(JSON.stringify(await signedurl_service_response.json()), {status: 200})}返されたトークンは12時間後に期限切れになります。
さらに一歩進めて、2つの追加制限を加えましょう:
- サインされたURLトークンをMP4ダウンロードに使用できるようにする(動画のダウンロードが有効になっていると仮定)
- 米国およびメキシコのユーザーが動画を視聴またはダウンロードできないようにする
これを実現するために、サンプルコードのsigned_url_restrictionsオブジェクトに追加の制限を指定できます:
addEventListener('fetch', event => { event.respondWith(handleRequest(event))})
async function handleRequest(request) {
var signed_url_restrictions = { //次の2時間の視聴を制限 exp: Math.floor(Date.now() / 1000) + (12*60*60), downloadable: true, accessRules:[{"type":"ip.geoip.country","country":["US","MX"],"action":"block"}] };
const init = { method: 'POST', headers: { "Authorization": "Bearer <API_TOKEN>", "content-type": "application/json;charset=UTF-8" }, body: JSON.stringify(signed_url_restrictions) } const signedurl_service_response = await fetch("https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/{video_uid}/token", init) return new Response(JSON.stringify(await signedurl_service_response.json()), {status: 200})}大量のトークンを生成する場合は、毎回Stream APIを呼び出すことなく新しいトークンを生成するのが最適です。
curl --request POST \"https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/keys" \--header "Authorization: Bearer <API_TOKEN>"レスポンスにはpemおよびjwkの値が返されます。
{ "result": { "id": "8f926b2b01f383510025a78a4dcbf6a", "pem": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBemtHbXhCekFGMnBIMURiWmgyVGoyS3ZudlBVTkZmUWtNeXNCbzJlZzVqemRKTmRhCmtwMEphUHhoNkZxOTYveTBVd0lBNjdYeFdHb3kxcW1CRGhpdTVqekdtYW13NVgrYkR3TEdTVldGMEx3QnloMDYKN01Rb0xySHA3MDEycXBVNCtLODUyT1hMRVVlWVBrOHYzRlpTQ2VnMVdLRW5URC9oSmhVUTFsTmNKTWN3MXZUbQpHa2o0empBUTRBSFAvdHFERHFaZ3lMc1Vma2NsRDY3SVRkZktVZGtFU3lvVDVTcnFibHNFelBYcm9qaFlLWGk3CjFjak1yVDlFS0JCenhZSVEyOVRaZitnZU5ya0t4a2xMZTJzTUFML0VWZkFjdGkrc2ZqMkkyeEZKZmQ4aklmL2UKdHBCSVJZVDEza2FLdHUyYmk0R2IrV1BLK0toQjdTNnFGODlmTHdJREFRQUJBb0lCQUYzeXFuNytwNEtpM3ZmcgpTZmN4ZmRVV0xGYTEraEZyWk1mSHlaWEFJSnB1MDc0eHQ2ZzdqbXM3Tm0rTFVhSDV0N3R0bUxURTZacy91RXR0CjV3SmdQTjVUaFpTOXBmMUxPL3BBNWNmR2hFN1pMQ2wvV2ZVNXZpSFMyVDh1dGlRcUYwcXpLZkxCYk5kQW1MaWQKQWl4blJ6UUxDSzJIcmlvOW1KVHJtSUUvZENPdG80RUhYdHpZWjByOVordHRxMkZrd3pzZUdaK0tvd09JaWtvTgp2NWFOMVpmRGhEVG0wdG1Vd0tLbjBWcmZqalhRdFdjbFYxTWdRejhwM2xScWhISmJSK29PL1NMSXZqUE16dGxOCm5GV1ZEdTRmRHZsSjMyazJzSllNL2tRVUltT3V5alY3RTBBcm5vR2lBREdGZXFxK1UwajluNUFpNTJ6aTBmNloKdFdvwdju39xOFJWQkwxL2tvWFVmYk00S04ydVFadUdjaUdGNjlCRDJ1S3o1eGdvTwowVTBZNmlFNG9Cek5GUW5hWS9kayt5U1dsQWp2MkgraFBrTGpvZlRGSGlNTmUycUVNaUFaeTZ5cmRkSDY4VjdIClRNRllUQlZQaHIxT0dxZlRmc00vRktmZVhWY1FvMTI1RjBJQm5iWjNSYzRua1pNS0hzczUyWE1DZ1lFQTFQRVkKbGIybDU4blVianRZOFl6Uk1vQVo5aHJXMlhwM3JaZjE0Q0VUQ1dsVXFZdCtRN0NyN3dMQUVjbjdrbFk1RGF3QgpuTXJsZXl3S0crTUEvU0hlN3dQQkpNeDlVUGV4Q3YyRW8xT1loMTk3SGQzSk9zUythWWljemJsYmJqU0RqWXVjCkdSNzIrb1FlMzJjTXhjczJNRlBWcHVibjhjalBQbnZKd0k5aUpGVUNnWUVBMjM3UmNKSEdCTjVFM2FXLzd3ekcKbVBuUm1JSUczeW9UU0U3OFBtbHo2bXE5eTVvcSs5aFpaNE1Fdy9RbWFPMDF5U0xRdEY4QmY2TFN2RFh4QWtkdwpWMm5ra0svWWNhWDd3RHo0eWxwS0cxWTg3TzIwWWtkUXlxdjMybG1lN1JuVDhwcVBDQTRUWDloOWFVaXh6THNoCkplcGkvZFhRWFBWeFoxYXV4YldGL3VzQ2dZRUFxWnhVVWNsYVlYS2dzeUN3YXM0WVAxcEwwM3h6VDR5OTBOYXUKY05USFhnSzQvY2J2VHFsbGVaNCtNSzBxcGRmcDM5cjIrZFdlemVvNUx4YzBUV3Z5TDMxVkZhT1AyYk5CSUpqbwpVbE9ldFkwMitvWVM1NjJZWVdVQVNOandXNnFXY21NV2RlZjFIM3VuUDVqTVVxdlhRTTAxNjVnV2ZiN09YRjJyClNLYXNySFVDZ1lCYmRvL1orN1M3dEZSaDZlamJib2h3WGNDRVd4eXhXT2ZMcHdXNXdXT3dlWWZwWTh4cm5pNzQKdGRObHRoRXM4SHhTaTJudEh3TklLSEVlYmJ4eUh1UG5pQjhaWHBwNEJRNTYxczhjR1Z1ZSszbmVFUzBOTDcxZApQL1ZxUWpySFJrd3V5ckRFV2VCeEhUL0FvVEtEeSt3OTQ2SFM5V1dPTGJvbXQrd3g0NytNdWc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=", "jwk": "eyJ1c2UiOiJzaWciLCJrdHkiOiJSU0EiLCJraWQiOiI4ZjkyNmIyYjAxZjM4MzUxNzAwMjVhNzhhNGRjYmY2YSIsImFsZyI6IlJTMjU2IiwibiI6InprR214QnpBRjJwSDFEYlpoMlRqMkt2bnZQVU5GZlFrTXlzQm8yZWc1anpkSk5kYWtwMEphUHhoNkZxOTZfeTBVd0lBNjdYeFdHb3kxcW1CRGhpdTVqekdtYW13NVgtYkR3TEdTVldGMEx3QnloMDY3TVFvTHJIcDcwMTJxcFU0LUs4NTJPWExFVWVZUGs4djNGWlNDZWcxV0tFblREX2hKaFVRMWxOY0pNY3cxdlRtR2tqNHpqQVE0QUhQX3RxRERxWmd5THNVZmtjbEQ2N0lUZGZLVWRrRVN5b1Q1U3JxYmxzRXpQWHJvamhZS1hpNzFjak1yVDlFS0JCenhZSVEyOVRaZi1nZU5ya0t4a2xMZTJzTUFMX0VWZkFjdGktc2ZqMkkyeEZKZmQ4aklmX2V0cEJJUllUMTNrYUt0dTJiaTRHYi1XUEstS2hCN1M2cUY4OWZMdyIsImUiOiJBUUFCIiwiZCI6IlhmS3FmdjZuZ3FMZTktdEo5ekY5MVJZc1ZyWDZFV3RreDhmSmxjQWdtbTdUdmpHM3FEdU9henMyYjR0Um9mbTN1MjJZdE1UcG16LTRTMjNuQW1BODNsT0ZsTDJsX1VzNy1rRGx4OGFFVHRrc0tYOVo5VG0tSWRMWlB5NjJKQ29YU3JNcDhzRnMxMENZdUowQ0xHZEhOQXNJcllldUtqMllsT3VZZ1Q5MEk2MmpnUWRlM05oblN2MW42MjJyWVdURE94NFpuNHFqQTRpS1NnMl9sbzNWbDhPRU5PYlMyWlRBb3FmUld0LU9OZEMxWnlWWFV5QkRQeW5lVkdxRWNsdEg2Zzc5SXNpLU04ek8yVTJjVlpVTzdoOE8tVW5mYVRhd2xnei1SQlFpWTY3S05Yc1RRQ3VlZ2FJQU1ZVjZxcjVUU1Ai2odx5iT0xSX3BtMWFpdktyUSIsInAiOiI5X1o5ZUpGTWI5X3E4UlZCTDFfa29YVWZiTTRLTjJ1UVp1R2NpR0Y2OUJEMnVLejV4Z29PMFUwWTZpRTRvQnpORlFuYVlfZGsteVNXbEFqdjJILWhQa0xqb2ZURkhpTU5lMnFFTWlBWnk2eXJkZEg2OFY3SFRNRllUQlZQaHIxT0dxZlRmc01fRktmZVhWY1FvMTI1RjBJQm5iWjNSYzRua1pNS0hzczUyWE0iLCJxIjoiMVBFWWxiMmw1OG5VYmp0WThZelJNb0FaOWhyVzJYcDNyWmYxNENFVENXbFVxWXQtUTdDcjd3TEFFY243a2xZNURhd0JuTXJsZXl3S0ctTUFfU0hlN3dQQkpNeDlVUGV4Q3YyRW8xT1loMTk3SGQzSk9zUy1hWWljemJsYmJqU0RqWXVjR1I3Mi1vUWUzMmNNeGNzMk1GUFZwdWJuOGNqUFBudkp3STlpSkZVIiwiZHAiOiIyMzdSY0pIR0JONUUzYVdfN3d6R21QblJtSUlHM3lvVFNFNzhQbWx6Nm1xOXk1b3EtOWhaWjRNRXdfUW1hTzAxeVNMUXRGOEJmNkxTdkRYeEFrZHdWMm5ra0tfWWNhWDd3RHo0eWxwS0cxWTg3TzIwWWtkUXlxdjMybG1lN1JuVDhwcVBDQTRUWDloOWFVaXh6THNoSmVwaV9kWFFYUFZ4WjFhdXhiV0ZfdXMiLCJkcSI6InFaeFVVY2xhWVhLZ3N5Q3dhczRZUDFwTDAzeHpUNHk5ME5hdWNOVEhYZ0s0X2NidlRxbGxlWjQtTUswcXBkZnAzOXIyLWRXZXplbzVMeGMwVFd2eUwzMVZGYU9QMmJOQklKam9VbE9ldFkwMi1vWVM1NjJZWVdVQVNOandXNnFXY21NV2RlZjFIM3VuUDVqTVVxdlhRTTAxNjVnV2ZiN09YRjJyU0thc3JIVSIsInFpIjoiVzNhUDJmdTB1N1JVWWVubzIyNkljRjNBaEZzY3NWam55NmNGdWNGanNIbUg2V1BNYTU0dS1MWFRaYllSTFBCOFVvdHA3UjhEU0NoeEhtMjhjaDdqNTRnZkdWNmFlQVVPZXRiUEhCbGJudnQ1M2hFdERTLTlYVF8xYWtJNngwWk1Mc3F3eEZuZ2NSMF93S0V5Zzh2c1BlT2gwdlZsamkyNkpyZnNNZU9fakxvIn0=", "created": "2021-06-15T21:06:54.763937286Z" }, "success": true, "errors": [], "messages": []}これらの値を保存してください。再度表示されることはありません。後でトークンを生成するためにこれらの値を使用します。pemおよびjwkフィールドはbase64エンコードされていますので、使用する前にデコードする必要があります(この手順の例はステップ2に示されています)。
ステップ1でキーを生成したら、pemまたはjwkの値を使用して自己署名URLを生成できます。この方法を使用すると、新しいトークンを作成するたびにStream APIを呼び出す必要がありません。
以下は、60分で期限切れになり、UKからビデオにアクセスするユーザーのみに機能するトークンを生成するCloudflare Workerスクリプトの例です。2行目と3行目で、ステップ1からのidおよびjwkの値を設定します。
// グローバル変数const jwkKey = '{PRIVATE-KEY-IN-JWK-FORMAT}'const keyID = '<KEY_ID>'const videoUID = '<VIDEO_UID>'// expiresTimeInSはビデオの期限切れ時間(秒単位)const expiresTimeInS = 3600
// メイン関数async function streamSignedUrl () { const encoder = new TextEncoder() const expiresIn = Math.floor(Date.now() / 1000) + expiresTimeInS const headers = { "alg": "RS256", "kid": keyID } const data = { "sub": videoUID, "kid": keyID, "exp": expiresIn, "accessRules": [ { "type": "ip.geoip.country", "action": "allow", "country": [ "GB" ] }, { "type": "any", "action": "block" } ] }
const token = `${objectToBase64url(headers)}.${objectToBase64url(data)}`
const jwk = JSON.parse(atob(jwkKey))
const key = await crypto.subtle.importKey( "jwk", jwk, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256', }, false, [ "sign" ] )
const signature = await crypto.subtle.sign( { name: 'RSASSA-PKCS1-v1_5' }, key, encoder.encode(token) )
const signedToken = `${token}.${arrayBufferToBase64Url(signature)}`
return signedToken}
// ユーティリティ関数function arrayBufferToBase64Url(buffer) { return btoa(String.fromCharCode(...new Uint8Array(buffer))) .replace(/=/g, '') .replace(/\+/g, '-') .replace(/\//g, '_')}
function objectToBase64url(payload) { return arrayBufferToBase64Url( new TextEncoder().encode(JSON.stringify(payload)), )}Stream Playerを使用している場合は、ステップ2でWorkerから返されたトークンをビデオIDの代わりに挿入します:
<iframe src="https://customer-<CODE>.cloudflarestream.com/eyJhbGciOiJSUzI1NiIsImtpZCI6ImNkYzkzNTk4MmY4MDc1ZjJlZjk2MTA2ZDg1ZmNkODM4In0.eyJraWQiOiJjZGM5MzU5ODJmODA3NWYyZWY5NjEwNmQ4NWZjZDgzOCIsImV4cCI6IjE2MjE4ODk2NTciLCJuYmYiOiIxNjIxODgyNDU3In0.iHGMvwOh2-SuqUG7kp2GeLXyKvMavP-I2rYCni9odNwms7imW429bM2tKs3G9INms8gSc7fzm8hNEYWOhGHWRBaaCs3U9H4DRWaFOvn0sJWLBitGuF_YaZM5O6fqJPTAwhgFKdikyk9zVzHrIJ0PfBL0NsTgwDxLkJjEAEULQJpiQU1DNm0w5ctasdbw77YtDwdZ01g924Dm6jIsWolW0Ic0AevCLyVdg501Ki9hSF7kYST0egcll47jmoMMni7ujQCJI1XEAOas32DdjnMvU8vXrYbaHk1m1oXlm319rDYghOHed9kr293KM7ivtZNlhYceSzOpyAmqNFS7mearyQ/iframe" style="border: none;" height="720" width="1280" allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;" allowfullscreen="true"></iframe>独自のプレーヤーを使用している場合は、マニフェストURL内のビデオIDをtoken値に置き換えます:
https://customer-<CODE>.cloudflarestream.com/eyJhbGciOiJSUzI1NiIsImtpZCI6ImNkYzkzNTk4MmY4MDc1ZjJlZjk2MTA2ZDg1ZmNkODM4In0.eyJraWQiOiJjZGM5MzU5ODJmODA3NWYyZWY5NjEwNmQ4NWZjZDgzOCIsImV4cCI6IjE2MjE4ODk2NTciLCJuYmYiOiIxNjIxODgyNDU3In0.iHGMvwOh2-SuqUG7kp2GeLXyKvMavP-I2rYCni9odNwms7imW429bM2tKs3G9INms8gSc7fzm8hNEYWOhGHWRBaaCs3U9H4DRWaFOvn0sJWLBitGuF_YaZM5O6fqJPTAwhgFKdikyk9zVzHrIJ0PfBL0NsTgwDxLkJjEAEULQJpiQU1DNm0w5ctasdbw77YtDwdZ01g924Dm6jIsWolW0Ic0AevCLyVdg501Ki9hSF7kYST0egcll47jmoMMni7ujQCJI1XEAOas32DdjnMvU8vXrYbaHk1m1oXlm319rDYghOHed9kr293KM7ivtZNlhYceSzOpyAmqNFS7mearyQ/manifest/video.m3u8
最大1,000個のキーを作成し、都合に応じてローテーションできます。 取り消されると、そのキーで作成されたすべてのトークンは無効になります。
curl --request DELETE \"https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/keys/{key_id}" \--header "Authorization: Bearer <API_TOKEN>"
# レスポンス:{ "result": "Revoked", "success": true, "errors": [], "messages": []}| プロパティ名 | 説明 | |
|---|---|---|
| exp | 有効期限。トークンが機能しなくなるUnixエポックタイムスタンプ。トークンが署名されてから24時間以上先であってはならない | |
| nbf | Not Before 値。トークンが機能しないUnixエポックタイムスタンプ | |
| downloadable | trueの場合、トークンはmp4をダウンロードするために使用できます(ビデオにダウンロードが有効になっていると仮定) | |
| accessRules | 1つ以上のIPおよび地理的制限を指定する配列。accessRulesは最初から最後まで評価されます。ルールが一致した場合、関連するアクションが適用され、さらに他のルールは評価されません。トークンはaccessRules配列に最大5つのメンバーを持つことができます。 |
各accessRuleは2つの必須プロパティを含む必要があります:
type: サポートされている値はany、ip.src、およびip.geoip.countryaction: サポートされている値はallowおよびblock
ルールの種類に応じて、accessRulesは2つの追加プロパティをサポートします:
country: 2文字の国コードの配列で、ISO 3166-1 Alpha 2 ↗形式です。ip: IPレンジの配列です。可能であれば、ルールにはIPv4とIPv6の両方のバリアントを含めることをお勧めします。ルールに単一のバリアントのみがある場合、そのルールは他のバリアントを無視します。たとえば、IPv4ベースのルールは、IPv6アドレスから接続しているビューアには適用されません。CIDRは特定のIPアドレスよりも優先されるべきです。一部のデバイス(モバイルなど)は、ビューの過程でIPを変更することがあります。ビデオアクセス制御は、ビデオが視聴されている間、継続的に評価されます。その結果、過度に厳しいIPルールは再生を妨げる可能性があります。
例 1: 特定の国からのビューをブロック
..."accessRules": [ { "type": "ip.geoip.country", "action": "block", "country": ["US", "DE", "MX"], },]最初のルールは、ここで国、US、DE、MXに一致します。そのルールが一致すると、ブロックアクションはトークンを無効と見なします。最初のルールが一致しない場合、評価するルールはありません。この状況での動作は、トークンを有効と見なすことです。
例 2: 特定の国またはIPからのビューのみを許可
..."accessRules": [ { "type": "ip.geoip.country", "country": ["US", "MX"], "action": "allow", }, { "type": "ip.src", "ip": ["93.184.216.0/24", "2400:cb00::/32"], "action": "allow", }, { "type": "any", "action": "block", },]最初のルールは、ここで国、USとMXに一致します。そのルールが一致すると、許可アクションはトークンを有効と見なします。一致しない場合は、ルールの評価を続けます。
2番目のルールはCIDRに一致するIPルールで、93.184.216.0/24と2400:cb00::/32です。そのルールが一致すると、許可アクションはルールを有効と見なします。
最初の2つのルールが一致しない場合、最終ルールのanyは残りのリクエストすべてに一致し、それらのビューをブロックします。
デフォルトでは、Streamの埋め込みコードは任意のドメインで使用できます。必要に応じて、Streamダッシュボードからビデオを埋め込むことができるドメインを制限できます。
ダッシュボードでは、各ビデオの横に「カンマで区切られた許可されたオリジンドメインを入力」とラベル付けされたテキストボックスが表示されます。これをクリックすると、Stream埋め込みコードが使用できるドメインをリストできます。
*.badtortilla.comは a.badtortilla.com、a.b.badtortilla.com をカバーし、badtortilla.com はカバーしませんexample.comは www.example.com ↗ や example.com のサブドメインをカバーしませんlocalhostは、ポート80でHTTPで提供されていない場合やポート443でHTTPSで提供されていない場合、ポートが必要です- パスのサポートはありません -
example.comは example.com/* をカバーします
Stream APIを使用してプログラム的に埋め込み制限を制御することもできます。以下の例の uid はビデオIDを指します。
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/{video_uid} \--header "Authorization: Bearer <API_TOKEN>" \--data "{\"uid\": \"<VIDEO_UID>\", \"allowedOrigins\": [\"example.com\"]}"サイン付きURLと埋め込み制限を組み合わせることで、ビデオの視聴方法を強力に制御できます。これにより、信頼できるユーザーのみを提供し、サイン付きURLが不明なサイトでホストされるのを防ぐことができます。