← Cloudflare Stream / stream / viewing-videos
Защита Stream
Подписанные URL-адреса и токены
По умолчанию видео в Stream доступно для просмотра любому, у кого есть его video id. Если вы хотите сделать видео закрытым по умолчанию и предоставлять доступ только определённым пользователям, используйте функцию подписанных URL. Если для видео включено требование подписанного URL, оно больше не доступно публично только по video id: пользователю понадобится токен подписанного URL, чтобы посмотреть или скачать видео.
Ниже перечислены распространенные сценарии использования подписанных URL-адресов:
- Ограничение доступа: определённое видео могут смотреть только авторизованные пользователи
- Позвольте пользователям смотреть видео в течение ограниченного времени (например, 24 часа)
- Ограничение доступа по геолокации
Требование подписанных URL-адресов для видео
Включите requireSignedURLs чтобы защитить видео с помощью подписанных URL. Эта опция запрещает любые публичные ссылки, например customer-<CODE>.cloudflarestream.com/<VIDEO_ID>/watch или встроенному плееру работать.
Ограничить просмотр можно, обновив метаданные видео.
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": []
}привязка Workers
Вы также можете потребовать подписанные URL-адреса с помощью привязки Stream в Worker. См. Привязка к Workers API для инструкций по настройке.
export default {
async fetch(request, env) {
const video = await env.STREAM.video("VIDEO_ID").update({
requireSignedURLs: true,
});
return Response.json(video);
},
};export default {
async fetch(request, env) {
const video = await env.STREAM.video("VIDEO_ID").update({
requireSignedURLs: true,
});
return Response.json(video);
},
};Три способа сгенерировать подписанные токены
Вы можете настроить своё приложение на создание токенов тремя способами:
-
Для низкой нагрузки или тестирования используйте
/tokenэндпоинт для генерации кратковременного подписанного токена. Это рекомендуется для тестирования или если вы генерируете менее 1000 токенов в день. Для этого нужно делать вызов API к Cloudflare для каждого токена, на который распространяется ограничение частоты запросов. Результат по умолчанию действителен 1 час. Этот метод не поддерживает Прямая трансляция через WebRTC. -
Рекомендуется: используйте ключ подписи для создания токенов. Если у вас тысячи пользователей в день или нужно генерировать большой объем токенов, как в случае с Прямая трансляция через WebRTC, вы можете самостоятельно создавать токены с помощью ключа подписи. Так вам не нужно вызывать Stream API каждый раз, когда требуется сгенерировать токен, и поэтому это не операция с ограничением частоты запросов.
-
Привязка Workers: используйте привязку Stream для генерации токенов. Если вы используете Cloudflare Workers с привязкой Stream, вы можете создавать токены напрямую, без отдельного вызова API и без управления ключами подписи. Это самый простой способ для пользователей Workers. Для расширенной настройки, например правил доступа или произвольного срока действия, используйте вместо этого ключ подписи.
Вариант 1: использование эндпоинта /token
Вы можете вызвать /token эндпоинт для любого видео, помеченного как приватное, чтобы получить токен подписанного URL со сроком действия один час. Этот метод не поддерживает Прямая трансляция через WebRTC.
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": []
}привязка Workers
Вы можете создать подписанный токен с помощью Stream binding:
export default {
async fetch(request, env) {
const token = await env.STREAM.video("VIDEO_ID").generateToken();
return Response.json({ token });
},
};export default {
async fetch(request, env) {
const token = await env.STREAM.video("VIDEO_ID").generateToken();
return Response.json({ token });
},
};Чтобы отобразить видео или использовать такие ресурсы, как манифесты или миниатюры, используйте token значение вместо идентификатора видео или входного потока. Например, чтобы использовать плеер Stream, замените идентификатор между cloudflarestream.com/ и /iframe на токен: https://customer-<CODE>.cloudflarestream.com/<TOKEN>/iframe.
<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>Аналогично, если вы используете собственный плеер, получите манифест HLS или DASH, заменив идентификатор видео в URL-адресе манифеста на token значение:
https://customer-<CODE>.cloudflarestream.com/<TOKEN>/manifest/video.m3u8https://customer-<CODE>.cloudflarestream.com/<TOKEN>/manifest/video.mpd
Настройка ограничений по умолчанию
Если вы вызываете /token эндпоинт без тела запроса, он вернёт токен со сроком действия один час без каких-либо иных ограничений или доступа к скачивания. Этот токен можно настроить, указав дополнительные свойства в запросе:
const signed_url_restrictions = {
// Extend the lifetime of the token to 12 hours:
exp: Math.floor(Date.now() / 1000) + 12 * 60 * 60,
// Allow access to MP4 or Audio Download URLs:
downloadable: true,
// Geo or IP access restrictions:
accessRules: {
// ... see examples below
}
};
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 },
);Однако если вы генерируете токены программно или добавляете подобные настройки, быстрее и масштабируемее использовать ключ подписи и создавать токен полностью на стороне вашего приложения.
Вариант 2: использование Stream binding
Если в Worker используется привязка Stream, можно создавать подписанные токены без отдельного вызова API к /token эндпоинт или самостоятельно управлять ключами подписи. Binding выполняет генерацию токенов внутри себя.
См. Привязка к Workers API для инструкций по настройке.
export default {
async fetch(request, env) {
const token = await env.STREAM.video("VIDEO_ID").generateToken();
return Response.json({ token });
},
};export default {
async fetch(request, env) {
const token = await env.STREAM.video("VIDEO_ID").generateToken();
return Response.json({ token });
},
};Токен, сформированный привязкой, по умолчанию действует один час. Если нужно настроить ограничения, такие как время действия, геолокация или доступ к скачиванию, используйте ключ для подписи чтобы создавать токены с пользовательскими claims.
Вариант 3: использование ключа подписи для создания подписанных токенов
Если вы создаете большое количество токенов, использование Прямая трансляция через WebRTC, или вам нужно настроить правила доступа, создавайте новые токены с помощью ключа подписи, чтобы не вызывать Stream API каждый раз.
Шаг 1: Вызовите /stream/key эндпоинт один раз чтобы получить ключ
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": []
}Эти значения больше не будут показаны, поэтому сразу сохраните их в надёжном месте. Если вы используете Cloudflare Workers, сохранить их можно с помощью Секреты. Если вы используете другую платформу, храните их в защищённых переменных окружения.
Эти значения понадобятся вам позже для создания токенов. Поля pem и jwk закодированы в base64, поэтому перед использованием их нужно декодировать (пример показан в шаге 2).
Шаг 2: Сгенерируйте токены с помощью ключа
После того как вы сгенерируете ключ на шаге 1, вы можете использовать pem или jwk значения, чтобы самостоятельно создавать самоподписанные URL. При таком подходе вам не нужно каждый раз вызывать Stream API при создании нового токена.
Ниже приведен пример скрипта Cloudflare Worker, который создает токены со сроком действия 60 минут и работают только для пользователей, просматривающих видео из Великобритании. В строках 2 и 3 вы настроите id и jwk значения из шага 1:
// Global variables
const jwkKey = "{PRIVATE-KEY-IN-JWK-FORMAT}";
const keyID = "<KEY_ID>";
const videoUID = "<VIDEO_UID>";
// expiresTimeInS is the expired time in second of the video
const expiresTimeInS = 3600;
// Main function
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,
// Add `downloadable` boolean for access to MP4 or Audio Downloads:
// downloadable: true,
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;
}
// Utilities functions
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)),
);
}Шаг 3: Рендеринг видео
Если вы используете Stream Player, вставьте token значение, возвращённое Worker на шаге 2, вместо video id, заменив всю строку, расположенную между cloudflarestream.com/ и /iframe:
<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>Если вы используете собственный плеер, замените video id в URL манифеста на token значение:
https://customer-<CODE>.cloudflarestream.com/eyJhbGciOiJSUzI1NiIsImtpZCI6ImNkYzkzNTk4MmY4MDc1ZjJlZjk2MTA2ZDg1ZmNkODM4In0.eyJraWQiOiJjZGM5MzU5ODJmODA3NWYyZWY5NjEwNmQ4NWZjZDgzOCIsImV4cCI6IjE2MjE4ODk2NTciLCJuYmYiOiIxNjIxODgyNDU3In0.iHGMvwOh2-SuqUG7kp2GeLXyKvMavP-I2rYCni9odNwms7imW429bM2tKs3G9INms8gSc7fzm8hNEYWOhGHWRBaaCs3U9H4DRWaFOvn0sJWLBitGuF_YaZM5O6fqJPTAwhgFKdikyk9zVzHrIJ0PfBL0NsTgwDxLkJjEAEULQJpiQU1DNm0w5ctasdbw77YtDwdZ01g924Dm6jIsWolW0Ic0AevCLyVdg501Ki9hSF7kYST0egcll47jmoMMni7ujQCJI1XEAOas32DdjnMvU8vXrYbaHk1m1oXlm319rDYghOHed9kr293KM7ivtZNlhYceSzOpyAmqNFS7mearyQ/manifest/video.m3u8
Чтобы разрешить доступ к Загрузки MP4 или аудио, убедитесь, что для видео уже включена возможность скачивания. Затем добавьте downloadable: true в полезную нагрузку, как показано в комментарии выше, при создании подписанного URL. Замените идентификатор видео в URL для скачивания на token значение:
https://customer-<CODE>.cloudflarestream.com/eyJhbGciOiJ.../downloads/default.mp4
Отзыв ключей
Вы можете создать до 1,000 ключей и менять их в любое удобное время. После отзыва ключа все токены, созданные с его помощью, становятся недействительными.
curl --request DELETE \
"https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/keys/{key_id}" \
--header "Authorization: Bearer <API_TOKEN>"
# Response:
{
"result": "Revoked",
"success": true,
"errors": [],
"messages": []
}Поддерживаемые ограничения
| Имя свойства | Описание | |
|---|---|---|
| exp | Срок действия. Временная метка unix epoch, после которой токен перестанет работать. Значение не может быть более чем на 24 часа позже момента подписания токена | |
| nbf | Не ранее значение. Метка времени unix epoch, до наступления которой токен не будет работать | |
| доступно для скачивания | если указано значение true, токен можно использовать для скачивания mp4 (при условии, что для видео включена загрузка) | |
| accessRules | Массив, задающий одно или несколько ограничений по IP и геолокации. Значения accessRules проверяются по порядку, от первого к последнему. Как только правило совпадает, применяется связанное с ним действие, а проверка остальных правил прекращается. В массиве accessRules у токена может быть не более 5 элементов. |
Схема accessRules
Каждое правило accessRule должно включать 2 обязательных свойства:
type: поддерживаются значенияany,ip.srcиip.geoip.countryaction: поддерживаются значенияallowиblock
В зависимости от типа правила accessRules поддерживает 2 дополнительных свойства:
country: массив двухбуквенных кодов стран в формате ISO 3166-1 Alpha 2 ↗ формате.ip: массив диапазонов IP-адресов. По возможности рекомендуется указывать в правиле оба варианта, IPv4 и IPv6. Если правило содержит только один из них, второй просто не учитывается: например, правило для IPv4 никогда не сработает для зрителя, подключившегося по IPv6. Вместо конкретных IP-адресов лучше использовать CIDR. У некоторых устройств, например мобильных, IP-адрес может меняться прямо во время просмотра. Video Access Control проверяется непрерывно, пока видео воспроизводится, поэтому слишком строгие правила по IP способны прервать воспроизведение.
Пример 1: блокировка просмотров из определённой страны
...
"accessRules": [
{
"type": "ip.geoip.country",
"action": "block",
"country": ["US", "DE", "MX"],
},
]Первое правило проверяет страну, в данном случае US, DE и MX. Если правило совпадает, действие block считает токен недействительным. Если первое правило не совпадает, дальнейшие правила не проверяются. В этом случае токен считается действительным.
Пример 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. Если правило совпадает, действие allow считает токен действительным. Если не совпадает, проверка переходит к следующим правилам
Второе правило представляет собой IP-правило, проверяющее CIDR-диапазоны 93.184.216.0/24 и 2400:cb00::/32. Если правило совпадает, действие allow считает его действительным.
Если первые два правила не сработали, последнее правило any применяется ко всем оставшимся запросам и блокирует эти просмотры.
Соображения по безопасности
Hotlinking Protection
По умолчанию код для встраивания Stream можно использовать на любом домене. При необходимости вы можете ограничить список доменов, на которых разрешено встраивание видео, в панели Stream.
В панели управления рядом с каждым видео вы увидите текстовое поле с меткой Enter allowed origin domains separated by commas. Нажав на неё, вы можете указать домены, на которых разрешено использовать код для вставки Stream.
`
*.badtortilla.comпокрываетa.badtortilla.com,a.b.badtortilla.comи не охватываетbadtortilla.comexample.comне покрывает www.example.com ↗ или любой поддомен example.comlocalhostтребует указания порта, если он не обслуживается по HTTP на порте 80 или по HTTPS на порте 443- Поддержка путей отсутствует,
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\"]}"Вы также можете задать разрешенные источники с помощью привязки Stream:
export default {
async fetch(request, env) {
const video = await env.STREAM.video("VIDEO_ID").update({
allowedOrigins: ["example.com"],
});
return Response.json(video);
},
};export default {
async fetch(request, env) {
const video = await env.STREAM.video("VIDEO_ID").update({
allowedOrigins: ["example.com"],
});
return Response.json(video);
},
};Allowed Origins
Функция Allowed Origins позволяет указать источники (origins), которым разрешено воспроизведение. Она работает даже при использовании собственного видеоплеера. В этом случае Allowed Origins ограничивает домены, с которых можно запрашивать манифесты HLS/DASH и сегменты видео.
Подписанные URL
Сочетание подписанных URL с ограничениями на встраивание позволяет строго контролировать просмотр видео. Так вы обслуживаете только доверенных пользователей и не даёте размещать подписанный URL на неизвестных сайтах.