INTEGRITY Документация

Защита Stream

Подписанные URL-адреса и токены

По умолчанию видео в Stream доступно для просмотра любому, у кого есть его video id. Если вы хотите сделать видео закрытым по умолчанию и предоставлять доступ только определённым пользователям, используйте функцию подписанных URL. Если для видео включено требование подписанного URL, оно больше не доступно публично только по video id: пользователю понадобится токен подписанного URL, чтобы посмотреть или скачать видео.

Ниже перечислены распространенные сценарии использования подписанных URL-адресов:

Требование подписанных 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);
	},
};

Три способа сгенерировать подписанные токены

Вы можете настроить своё приложение на создание токенов тремя способами:

Вариант 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 значение:

Настройка ограничений по умолчанию

Если вы вызываете /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 значение:

Отзыв ключей

Вы можете создать до 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 обязательных свойства:

В зависимости от типа правила accessRules поддерживает 2 дополнительных свойства:

Пример 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. `

Вы также можете программно управлять ограничением встраивания через 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 на неизвестных сайтах.