SIRINVIDEO Документация администратора и интегратора На сайт 2026.08

Метки потоков (labels)

Как выдать доступ сразу группе потоков одной строкой в токене — и почему uuid с дефисами в JWT даёт 403.

Выдавать права по имени потока удобно, пока потоков десять. На тысяче камер токен, перечисляющий пути, становится неуправляемым: каждое добавление камеры требует перевыпуска всех токенов.

Метка решает это: непрозрачная строка, приклеенная к потоку. Право в токене выдаётся на метку, а не на путь, — и новая камера с той же меткой становится доступна без единого нового токена.

Ядро не приписывает метке никакого смысла: это не организация, не тег и не иерархия. Что она означает, решаете вы.

Как назначить метку потоку#

stream camA {
    input  rtsp://admin:пароль@10.0.0.10:554/Streaming/Channels/101;
    labels site-north tier-gold <UUID>;
}
Параметр Тип и допустимые значения По умолчанию Применение
labels список строк через пробел; ≤ 40 меток на поток; каждая 1…64 байта; без пробелов и управляющих символов [] — меток нет горячее

Метки — единственная часть блока потока, которая не входит в его отпечаток перезапуска. Поэтому их правка применяется вживую: поток не переподключается, зрители не разрываются, а снятая метка перестаёт авторизовывать со следующего медиа-запроса.

Метки правятся в панели управления

Форма потока → вкладка Access → поле Authorization labels. Там же живёт allowed_referers. Сохранение применяется горячо, ровно как правка файла.

Главная ловушка: uuid канонизируется в конфигурации, но не в токене#

Если метка выглядит как uuid, сервер приводит её к компактной 22-символьной форме base64url — чтобы два написания одного и того же uuid были одной идентичностью. Это преобразование применяется к меткам потоков и к меткам в конфигурации, но НЕ к меткам внутри JWT: их сравнивают байт в байт с тем, что уже лежит в памяти сервера.

в конфигурации:  labels 3f2504e0-4f89-11d3-9a0c-0305e82c3301;
в памяти:        PyUE4E-JEdOaDAMF6CwzAQ
в токене нужна:  PyUE4E-JEdOaDAMF6CwzAQ      ← а не форма с дефисами

Проверено на стенде, поток с меткой-uuid из примера выше:

Где записана метка Форма записи Результат
конфигурация: permission read label=3f2504e0-…-3301 с дефисами 200
конфигурация: permission read label=PyUE4E-JEdOaDAMF6CwzAQ b64u22 200
JWT: "labels":["3f2504e0-…-3301"] с дефисами 403
JWT: "labels":["PyUE4E-JEdOaDAMF6CwzAQ"] b64u22 200

Преобразование — это base64url без выравнивания от 16 байт uuid:

python3 -c "
import base64, sys
u = sys.argv[1].replace('-', '')
print(base64.urlsafe_b64encode(bytes.fromhex(u)).rstrip(b'=').decode())
" 3f2504e0-4f89-11d3-9a0c-0305e82c3301
PyUE4E-JEdOaDAMF6CwzAQ
Отладка этой ошибки выглядит как проблема прав

Токен подписан верно, срок не истёк, поток на месте — а ответ 403. Первым делом сверьте форму метки в токене с той, что сервер держит в памяти. Готовая функция label_from_uuid() есть в обоих скриптах на странице Генераторы токенов.

Если вы не используете uuid в метках, ловушки нет: site-north остаётся site-north везде.

Две формы права по метке#

Форма 1 — обычное разрешение с полем labels#

Выдаёт действие (read, playback, publish):

{"action":"read","labels":["site-north"],"protocols":["hls"]}

Совпадение — точное строковое равенство с любой из меток потока. Ни глоба, ни префикса, ни регистронезависимости: site-* и SITE-NORTH не совпадут с site-north (проверено, 403).

Поле path можно не указывать вовсе — тогда правило работает исключительно по меткам.

Форма 2 — компактный грант-строка#

Выдаёт биты привилегий (live, dvr, export, preview) и записывается одной строкой <метка>.<маска-hex>:

{"grants":["PyUE4E-JEdOaDAMF6CwzAQ.03", "*.20"]}

Метка здесь обязана быть корректной 22-символьной формой base64url; * означает «любой поток». Некорректная строка молча отбрасывается — токен остаётся валидным, но это право в нём просто не считается.

Маска Биты Что открывает
01 live живой просмотр любым протоколом
02 dvr DVR, таймшифт, VoD
03 live + dvr живое и архив
10 export скачивание клипа
20 preview только preview.mp4
33 всё перечисленное максимум, который сервер умеет проверять

Обе формы можно смешивать в одном массиве прав.

Когда нужна вторая форма

Только тогда, когда права надо разрезать внутри архива: выдать «скачать клип, но не смотреть». Обычное разрешение с action: playback открывает и просмотр архива, и экспорт одновременно, потому что путь совпал. Компактный грант *.10 даёт ровно экспорт.

Сопоставление: всюду ИЛИ#

Ситуация Правило
у потока несколько меток достаточно совпасть одной
в одном разрешении несколько меток достаточно совпасть одной
в токене несколько разрешений достаточно сработать одному
несколько компактных грантов маски объединяются
путь и метки внутри одного разрешения совпал путь или совпала метка

Пересечения (И) в системе меток нет нигде. Сужают доступ только action, protocols, привязка к IP и замок Referer из токена — но не метки.

Отсюда важное: приоритета у путей и меток нет и запретить меткой нельзя. Метка умеет только добавлять доступ.

Поток без меток#

Множество меток пусто, поэтому:

  • правило только по меткам такому потоку не подойдёт — 403;
  • правило по пути (path) работает как обычно;
  • компактный грант *.<маска> сработает: подстановочный знак пересекается с любым набором меток, включая пустой.

Метки и public_paths#

Механизмы независимы и срабатывают на разных этапах. public_paths проверяется первым и полностью снимает авторизацию для пути; метки участвуют позже, когда бэкенд уже разбирает грант.

Практически это значит: метка не может сделать поток публичным, а public_paths не смотрит на метки — только на путь. Есть и разница в кэшировании: путь из public_paths сохраняет кэшируемость сегментов, «открытый меткой» — нет (см. Авторизация просмотра).

Разобранные примеры#

Конфигурация во всех примерах:

auth_backend { type hs256; secret "секрет-подписи-токенов-зрителей"; }

stream camA { input rtsp://10.0.0.10:554/live; labels <UUID> site-north; }
stream camB { input rtsp://10.0.0.11:554/live; labels site-north; }
stream camC { input rtsp://10.0.0.12:554/live; }

где <UUID> = 3f2504e0-4f89-11d3-9a0c-0305e82c3301. После загрузки конфигурации метки camA — это ["PyUE4E-JEdOaDAMF6CwzAQ", "site-north"]: uuid канонизирован, набор отсортирован и очищен от повторов.

Пример 1 — доступ к группе по общей метке#

{"exp":1787200000,"grants":[{"action":"read","labels":["site-north"]}]}
Поток Вердикт Почему
camA 200 site-north есть в метках
camB 200 site-north есть в метках
camC 403 меток нет, пути в правиле тоже нет

Пример 2 — метка-uuid записана не в той форме#

{"exp":1787200000,"grants":[{"action":"read","labels":["3f2504e0-4f89-11d3-9a0c-0305e82c3301"]}]}
Поток Вердикт Почему
camA 403 у потока метка уже PyUE4E-JEdOaDAMF6CwzAQ; строки не равны
camB, camC 403 такой метки у них нет

Тот же uuid в форме ["PyUE4E-JEdOaDAMF6CwzAQ"] → camA 200, camB и camC 403.

Пример 3 — путь и метка в одном разрешении складываются по ИЛИ#

{"exp":1787200000,"grants":[{"action":"read","path":"camB","labels":["PyUE4E-JEdOaDAMF6CwzAQ"]}]}
Поток Вердикт Почему
camA 200 путь не совпал, но совпала метка
camB 200 метка не совпала, но совпал путь
camC 403 не совпало ничего

Пример 4 — компактные гранты разрезают привилегии#

{"exp":1787200000,"grants":["*.02"]}   // только dvr
{"exp":1787200000,"grants":["*.10"]}   // только export
{"exp":1787200000,"grants":["*.12"]}   // dvr и export
Токен timeshift-…m3u8 dvr/clip?from&to index.m3u8 (живое)
*.02 200 403 403
*.10 403 200 403
*.12 200 200 403

Живой просмотр требует бита live (01) — ни dvr, ни export его не дают. Это единственный способ выдать право «только скачать клип» без права смотреть.

Проверка#

Метка в токене совпала с меткой потока

Выпустите токен по метке (см. пресет label в генераторе) и запросите плейлист потока, у которого эта метка есть, и потока, у которого её нет.

curl -s -o /dev/null -w '%{http_code}\n' \
  "http://media.example.com:8080/camA/index.m3u8?token=$TOKEN"
curl -s -o /dev/null -w '%{http_code}\n' \
  "http://media.example.com:8080/camC/index.m3u8?token=$TOKEN"
200
403

403 на обоих потоках при живом camA — почти наверняка форма метки: сверьте её с выводом label_from_uuid().