流鉴权
Monibuca v6 支持三种互补的流鉴权 / 准入能力:
- 内置签名鉴权(
secret+expire,MD5) - 自定义鉴权处理器(在
enable_auth开启时优先于 MD5) - Signed Policy(HMAC-SHA256 URL/query 门禁,独立于
enable_auth)
另有同步 admission webhook(HTTP 准入),在 verify_stream_auth 之后由协议钩子调用,语义不变。
每个推流/拉流请求按以下顺序过闸,任一环节失败即拒绝:
- MD5 / 自定义处理器(仅当
enable_auth: true且配置了 key) - Signed Policy(当
signed_policy启用且 action/protocol 匹配) - Admission webhook(当
admission_webhook启用且 action/protocol 匹配;可改写stream_path)
三者相互独立、可任意组合;全部关闭时保持零开销的默认行为。
协议(protocol 取值) | 推流(publish) | 拉流(play) | 说明 |
|---|---|---|---|
rtmp | ✅ | ✅ | 拒绝时直接断开连接 |
webrtc | ✅ WHIP | ✅ WHEP | 拒绝时返回 HTTP 401 |
srt | ✅ | ✅ | 握手阶段以 Unauthorized 拒绝 |
rtsp | ✅ record/announce | ✅ describe/play | RTSP 401 |
webtransport | ✅ | ✅ | 会话关闭 |
hls | — | ✅ | 仅 playlist/master 走准入;.ts/分片只做鉴权 |
flv | — | ✅ | HTTP-FLV 与 WS-FLV |
mp4 | — | ✅ | HTTP MP4 拉流 |
表中 protocol 取值同时用于 Signed Policy 的 protocols 过滤、admission webhook 的 protocols 过滤及请求体中的 protocol 字段。
启用内置鉴权
Section titled “启用内置鉴权”global: enableauth: true publish: key: "your-publish-key" secretargname: secret expireargname: expire subscribe: key: "your-subscribe-key"说明:
enableauth=true时开启鉴权逻辑- 推流使用
publish.key - 拉流使用
subscribe.key - 参数名可通过
secretargname/expireargname覆盖,默认分别是secret/expire
签名计算:
secret = md5(key + streamPath + expireHex)其中:
key:publish.key或subscribe.keystreamPath:不含 query 的流路径(如live/test)expireHex:16 进制 Unix 时间戳(秒)
校验规则:
expire必须可解析为 16 进制时间戳,且未过期secret长度必须为 32secret与服务端计算值(忽略大小写)一致
URL 示例
Section titled “URL 示例”以 live/test 为例:
rtmp://host/live/test?secret=...&expire=...http://host:8180/flv/live/test.flv?secret=...&expire=...http://host:8180/hls/live/test/index.m3u8?secret=...&expire=...http://host:8180/webrtc/push/live/test?secret=...&expire=...http://host:8180/webrtc/play/live/test?secret=...&expire=...srt://host:6000?streamid=publish:/live/test?secret=...&expire=...准入 Webhook(admission_webhook)
Section titled “准入 Webhook(admission_webhook)”除本地 secret+expire / 自定义处理器外,可配置同步 HTTP 准入 Webhook(OME AdmissionWebhooks 风格),在创建推流/拉流会话前向控制面询问 allow/deny,并支持改写 stream_path。
覆盖协议见上文协议覆盖表。
global: admission_webhook: enable: false url: "https://ctrl.example/v1/admission" secret: "shared-secret" # 可选;设置后发送 X-Monibuca-Signature: sha256=<hex> timeout_ms: 3000 # 单次请求硬超时(毫秒),不重试 fail_policy: closed # closed | open(仅 opening 生效) notify_closing: false # 会话结束时 best-effort POST status=closing actions: [publish, play] # 省略 = 两者 protocols: [webrtc, rtmp] # 省略 = 全部已接入协议路径改写由 admission 在 Signed Policy 校验之后发生;MVP 下 policy 绑定的是客户端请求的原始 stream_path。
Monibuca 向 url 发送 POST JSON,请求头包含 X-Monibuca-Event: admission.opening、X-Monibuca-Delivery(幂等 ID),以及可选的 X-Monibuca-Signature: sha256=<hex>(对请求体做 HMAC-SHA256):
{ "action": "publish", "protocol": "rtmp", "status": "opening", "stream_path": "live/cam01", "url": "rtmp://host/live/cam01?token=abc", "client": { "ip": "203.0.113.7", "port": 51234, "user_agent": "OBS" }, "query": { "token": "abc" }, "session_id": null, "time": "2026-07-17T12:00:00Z"}控制面返回 2xx + JSON:
{ "allowed": true, "stream_path": "live/real-cam01", "reason": "ok"}| 字段 | 必填 | 说明 |
|---|---|---|
allowed | 是 | 缺失或 false 均视为拒绝 |
stream_path | 否 | 改写后的流路径(仅路径,不含 host/协议) |
lifetime_ms | 否 | 已记录但 MVP 未强制执行(HLS/FLV/MP4 分片 GET 不受控) |
reason | 否 | 建议仅在控制面侧记录;客户端只收到 401 等通用错误 |
fail_policy
Section titled “fail_policy”closed(默认)在超时/网络错误/非 2xx/无效 JSON 时拒绝;open 在同样故障时放行并输出 warn 日志(仅建议开发环境)。
notify_closing
Section titled “notify_closing”当 enable 且 notify_closing: true 时,会话型协议在会话正常结束时会向控制面 fire-and-forget POST(status: "closing",头 X-Monibuca-Event: admission.closing)。响应体忽略;失败只打 warn,不阻塞 teardown,也不套用 fail_policy。
| 会发 closing | 不发 closing |
|---|---|
| WebRTC WHIP/WHEP、RTMP、SRT | HLS / HTTP-FLV / MP4(无持久会话) |
| RTSP / WebTransport(本切片暂未接线) |
- HLS 仅在请求 playlist/master 时走准入;
.ts/ fMP4 分片 GET 只做鉴权,不逐个回源准入。 enable: false或未配置时为零开销,不改变现有默认行为。
Signed Policy(HMAC URL 门禁)
Section titled “Signed Policy(HMAC URL 门禁)”OME SignedPolicy 风格的本地确定性鉴权:对 protocol + action + stream_path + expire 做 HMAC-SHA256,token 放在 query 中。与 enable_auth、admission webhook 互补,默认关闭。
global: signed_policy: enable: false secret: "your-hmac-secret" token_query: "policy" # token 参数名 expire_query: "expire" # 过期时间参数名(十进制 Unix 秒) algorithm: "hmac-sha256" # MVP 仅支持此项 actions: ["publish", "play"] protocols: [] # 空 = 全部协议;如 ["rtmp", "webrtc"]说明:
enable=false或secret为空:零开销 no-opactions/protocols未匹配时跳过(不要求 token)- Signed Policy 的
expire为十进制 Unix 秒;MD5 鉴权的expire为十六进制。若两者同时开启且共用参数名,请将其一的expire_query/expireargname改成不同名字
Canonical 字符串与签名
Section titled “Canonical 字符串与签名”canonical = "v1\n" + protocol + "\n" + action + "\n" + stream_path + "\n" + expirepolicy = hex(HMAC-SHA256(secret, canonical))其中:
protocol:插件名(如rtmp、webrtc、hls、flv、srt)action:publish或playstream_path:不含 query 的流路径(如live/test)expire:十进制 Unix 时间戳(秒)
生成示例(Python)
Section titled “生成示例(Python)”import hmac, hashlib, time
secret = b"your-hmac-secret"protocol = "rtmp"action = "play"stream_path = "live/test"expire = str(int(time.time()) + 3600)canonical = f"v1\n{protocol}\n{action}\n{stream_path}\n{expire}"policy = hmac.new(secret, canonical.encode(), hashlib.sha256).hexdigest()print(f"?policy={policy}&expire={expire}")生成示例(Shell / openssl)
Section titled “生成示例(Shell / openssl)”SECRET="your-hmac-secret"PROTOCOL="rtmp"ACTION="play"STREAM_PATH="live/test"EXPIRE=$(( $(date +%s) + 3600 ))
POLICY=$(printf 'v1\n%s\n%s\n%s\n%s' "$PROTOCOL" "$ACTION" "$STREAM_PATH" "$EXPIRE" \ | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')
echo "?policy=${POLICY}&expire=${EXPIRE}"URL 示例
Section titled “URL 示例”rtmp://host/live/test?policy=...&expire=1735689600http://host:8180/hls/live/test/index.m3u8?policy=...&expire=1735689600失败时返回与现有鉴权相同的 auth error(缺失 / 过期 / 签名错误均拒绝)。
自定义鉴权处理器
Section titled “自定义鉴权处理器”当你希望接入外部用户系统、权限中心或一次性票据时,可注册自定义鉴权处理器。
行为优先级(在 enable_auth 路径内):
- 自定义处理器(如果已注册)
- 内置
secret+expire鉴权
自定义处理器返回后,若开启了 Signed Policy 且匹配 action/protocol,仍须通过 Signed Policy。
StreamManagerApi 提供:
set_stream_auth_handler(handler)
处理器签名:
- 输入:
StreamAuthRequestplugin_namestream_pathquery_stringparams(已解析 query map)is_publish
- 返回:
Result<()>Ok(()):鉴权通过Err(...):鉴权失败
manager.set_stream_auth_handler(Some(Arc::new(|req| { if req.plugin_name == "rtmp" && req.is_publish { let token = req.params.get("token").cloned().unwrap_or_default(); if token == "allow" { return Ok(()); } return Err(sdk::MonibucaError::InvalidInput("auth failed".into())); } Ok(())})));Admin / 全局配置页入口
Section titled “Admin / 全局配置页入口”signed_policy 与 admission_webhook 均已注册到全局配置页(/config 下的全局配置表单,即 Admin 的配置入口),分别位于「Signed Policy 门禁」与「准入 Webhook」分组,字段与上文 YAML 一一对应(密钥字段以密码框展示)。
注意:
- 通过配置页保存需要启用数据库(DB 配置持久化);未启用数据库时请直接编辑
config.yaml。 - 两个功能的开关都要求配套字段非空才生效(Signed Policy 需
secret,admission 需url),只勾选 enable 不会产生效果。
与 Admin 推流地址生成配合
Section titled “与 Admin 推流地址生成配合”Admin 的「推流地址」弹窗支持按相同规则自动生成:
expire(16 进制时间戳)secret(md5(key + streamPath + expire))
生成后会自动拼接到地址 query 中。
签名生成 API
Section titled “签名生成 API”服务端提供签名生成接口:
GET /v6/api/streams/secret?stream_path={streamPath}&type={publish|subscribe}&expire=<hex>&plugin=<pluginName>参数说明:
stream_path:流路径type:publish或subscribe,默认publishexpire:可选,16 进制 Unix 时间戳;不传默认当前时间 + 30 分钟plugin:可选,插件名(默认global,即使用全局继承 key)
返回示例:
{ "secret_type": "publish", "plugin": "rtmp", "stream_path": "live/test", "expire": "6610f4a0", "secret": "0123456789abcdef0123456789abcdef"}联系我们