Appearance
视频鉴权:签名 URL 与失效处理
如果你的视频不是公开的,需要控制"谁能看",这一页讲清楚 Sentinel 支持什么、不支持什么, 以及签名过期时会发生什么。
一、只有一种鉴权方式:签名 URL
把鉴权信息拼在 URL 上,由 CDN / 源站校验:
https://cdn.example.com/live/room-123.m3u8?token=eyJhbGc...&expires=1752800000&sig=a1b2c3参数名叫什么、怎么签、有效期多久,完全由你的 CDN 决定,SDK 不关心也不解析—— 它只负责把这个 URL 原样交给浏览器去请求。
不支持自定义请求头
source.headers / source.getHeaders 已被移除(ADR-022)。不要找了,没有。
原因是物理限制,不是我们偷懒:iOS Safari 播 HLS 时,.m3u8 和 .ts 的请求由 系统底层发出,JS 层根本拦不到,没有任何办法给它们加 header(坑 #26)。
如果保留 headers 能力,结果就是"在 Chrome 上测好了,上线后 iPhone 全挂"。 所以我们干脆不提供这个幻觉,强制所有人走签名 URL——这是唯一四端一致的方案。
二、关键认知:HLS 不是一个请求,是几百个
这是最容易翻车的地方。播一个 HLS 视频,浏览器实际发出的请求是:
master.m3u8 ← 主播放列表 1 个
└─ 720p.m3u8 ← 媒体播放列表 1 个(直播还会持续轮询刷新)
├─ seg-001.ts ← 分片
├─ seg-002.ts
└─ ... ← 每 2-10 秒一个,一小时的片子几百上千个每一个都是独立的 HTTP 请求,每一个都要通过 CDN 的鉴权。
所以签名的有效期不是"够打开播放器就行",而是必须覆盖整个观看时长。
典型事故
签名 TTL 设 5 分钟,自测时点开就播、一切正常。上线后用户看到第 6 分钟, 分片开始 403,画面卡死。而你的监控里"首帧成功率 100%"。
三、签名过期了会怎样
你会收到一个错误事件
vue
<script setup lang="ts">
import type { PlayerError } from '@sentinel-lab/video-vue-frame'
import { VideoPlayerFrame } from '@sentinel-lab/video-vue-frame'
const src = 'https://your-cdn/video.m3u8'
function onError(e: PlayerError) {
if (e.code === 'E_AUTH_EXPIRED') {
// 签名失效了
}
}
</script>
<template>
<VideoPlayerFrame :source="src" @error="onError" />
</template>| 错误码 | 触发条件 | retryable |
|---|---|---|
E_AUTH_EXPIRED | 分片 / 播放列表请求返回 401 或 403 | false |
为什么 403 也算"过期"而不是"无权限"
CDN 上签名过期返回的通常就是 403,和"这个用户本来就没权限"用的同一个状态码, 从 HTTP 层无法区分。所以统一按签名过期处理——这两种情况下业务方要做的事 恰好也一样:去重新取一个 URL。
retryable: false 是什么意思
意思是原样重试没有意义。SDK 不会自动重连,因为拿同一个过期 URL 再请求一百次, 一百次都是 403。
SDK 不会替你刷新签名(ADR-022)。它不知道你的签发接口在哪、要带什么参数、 用户当前的登录态是什么。这件事只能业务层做。
四、怎么恢复
React / Vue(inline 或 iframe)—— 宿主完整换源后重建
业务层拿到新授权后,向自己的服务请求完整的新 MediaSource,再以递增的组件 key 重建播放器。 消费组件不暴露 load();更重要的是,FLV/HLS 内核变化和直播/点播语义变化不能热切,权益变化不应由 前端猜测浏览器最终选中的内核。
宿主维护的事务应当是:
- 保存点播位置和用户的播放/暂停意图;直播不保存旧时间点。
- 请求服务端按当前权益签发完整新源。多清晰度由新的 HLS Master Playlist 决定,不在前端拼“高清 URL”。
- 更新
source并递增 Reactkey/ Vue:key,让新播放器建立新的播放会话。 - 新播放器
ready后,点播恢复有效位置和播放意图;直播回新流 live edge。 - 仅当时间或画面真的推进后判定恢复成功;无权、下架和区域限制显示业务 CTA,不重连旧 URL。
用户是有感的
重建会重新缓冲,点播可能短暂闪动;直播会回到新流最新位置。这是安全的授权恢复路径,不是无感热更新。 签名 TTL 仍应覆盖合理播放窗口,以减少发生频率。
用户是有感的
这个过程会重新缓冲。点播会看到一次卡顿和进度条闪动;直播则会直接跳到最新位置。 它是兜底,不是解决方案——真正的解决方案是让签名别在观看途中过期。
静态 iframe URL —— 无法恢复
静态场景没有命令通道,你调不了 load。
唯一能做的是在宿主页面监听到 error 后,用新 URL 重建整个 iframe:
js
import { on } from '@sentinel-lab/video-embed-helper'
// ⚠️ 回调必须是 async —— 里面要 await 换签名。这一行此前漏了 `async`,照抄会语法错误
on('error', async (e) => {
if (e.code === 'E_AUTH_EXPIRED') {
iframe.src = buildEmbedUrl(await fetchSignedUrl()) // 整个播放器重来
}
})静态 iframe URL 没有通用 seek 句柄,不能承诺客户端续播;由服务端针对新源决定从头播还是提供可续播的 播放策略。
结论
需要鉴权的视频,不推荐用静态 iframe URL 接入。 如果非用不可,签名 TTL 必须给得非常宽裕。
五、推荐的签发规则
因为没有一个四端通用的逐分片无感改签方案,同时又要具备宿主完整换源兜底,我们的建议很直接:
1. TTL 要覆盖"最长可能的观看时长",再乘个系数
| 场景 | 建议 TTL |
|---|---|
| 短视频 / 预览片(< 5 分钟) | ≥ 30 分钟 |
| 长视频点播(电影、课程) | ≥ 视频时长 × 2,且不低于 6 小时 |
| 直播 | ≥ 6 小时,或用下面的方案 2 |
用户会暂停去吃饭、会切后台、会挂着不关。按"视频多长"算 TTL 是不够的。
2. 直播优先考虑 Cookie / 路径级鉴权
直播没有"总时长"可言,靠拉长 TTL 治标不治本。如果你的 CDN 支持,更好的做法是:
- 签名 Cookie(如 CloudFront Signed Cookies):鉴权信息放 Cookie,浏览器自动带上, 刷新 Cookie 不需要动播放器
- 路径级签名:签的是
/live/room-123/*整个路径而非单个文件,分片天然覆盖
这两种方案的共同好处:续期不需要重新 load,用户完全无感。
3. 分片和播放列表要用同一套签名策略
常见错误:只给 .m3u8 签了名,.ts 分片走另一条不鉴权的路径—— 那你的鉴权形同虚设,别人抓到分片 URL 就能直接下载。
反过来,如果 .m3u8 签名有效期长而 .ts 短,就会出现"能打开但播不动"。
4. 显式传 type
签名 URL 常常带一堆 query 参数,甚至路径里没有 .m3u8 后缀。 SDK 从后缀猜格式会猜错,建议一律显式指定:
js
{ url: signedUrl, type: 'hls' } // 别让它猜5. TTL 别设太长到失去意义
上面一直在说"设长点",但也别设成 30 天——那和不鉴权区别不大, URL 一旦泄露就是长期敞开。
推荐区间:够覆盖一次完整观看 + 合理余量,通常 6~24 小时是个平衡点。 如果你需要更严格的控制,走方案 2 的 Cookie 鉴权,而不是缩短 URL 签名 TTL。
六、其他要知道的
- URL 在所有接入方式下都是明文可见的。用户 F12 / 抓包就能拿到带 token 的完整 URL。 签名 URL 防的是"未授权用户直接访问",防不了"已授权用户把链接发给别人"。 真要防转发,得靠短 TTL + IP 绑定 + 单点播控,这些都在 CDN 侧做。
- 跨域要配 CORS。hls.js / flv.js 通过 JS 拉流,受同源策略约束, CDN 必须返回正确的
Access-Control-Allow-Origin。 ⚠️ 配错时拿不到专门的 CORS 错误码 —— xgplayer 把它报成普通网络错误, 你会收到E_NETWORK。真正确认要看 DevTools Console 里浏览器自己的 CORS 报错。 - ⚠️ 「iPhone 能播、Chrome 报 CORS」这条经验在 ADR-056 之后不再成立。ADR-056 之后 iOS ≥ 17.1 也走 hls.js(经
ManagedMediaSource), 分片同样由 JS 拉取、同样受同源策略约束 —— CDN 少配 CORS 的话 iPhone 会跟着一起报错。 只有 iOS < 17.1 回落原生 HLS 那一档才不走 CORS。 换句话说:CORS 现在是全平台必配项,别再拿 iPhone 能播当"配好了"的证据。
相关
- ADR-022 · 认证仅用签名 URL
- 错误码参考
- 怎么选视频源 —— § 7.1 讲了为什么签名 URL 要显式传
type