BroadcastChannel 实现跨标签页 SSO 状态同步,核心是状态变更后主动广播并监听响应:登录/登出完成且本地持久化后立即发送 type、timestamp 等结构化消息;各页初始化时监听同一频道,通过 fromTabId 避免自循环,幂等处理;不支持时降级为 localStorage + storage 事件;需注意同源限制、消息延迟及敏感信息禁止广播。
利用
实现跨标签页 SSO 状态同步,核心在于“状态变更时主动广播 + 各标签页监听并响应”,它不替代登录逻辑,而是补足浏览器多标签场景下的状态一致性。关键点是:SSO 登录/登出完成后的状态更新必须触发一次广播,且所有监听页需能安全、幂等地处理重复或延迟消息。
确保 SSO 状态变更后立即广播
在主登录页(如 OAuth 回调页)或登出页完成身份写入(如更新 localStorage、写入 cookie、设置 auth token)后,立刻用
发送结构化消息:
消息体建议包含
(如
或
)、
(毫秒时间戳)、可选的
或
避免在未确认登录成功前广播——例如等待后端接口返回 200 且本地持久化完成后再发
示例:
各标签页统一监听并响应状态变更
每个页面(包括已打开的旧标签)应在初始化阶段创建并监听同一频道,收到消息后执行本地状态刷新逻辑:
监听前先检查当前页面是否为“广播源”(可通过
判断,但更可靠的是加字段标识,如
),避免自己发的消息触发自身重复处理
响应动作应幂等:比如登出消息到达时,清空本地 token 并跳转登录页;若已登出,则忽略;可用
做前置校验
注意兼容性:Safari 15.4+、Chrome 54+、Firefox 58+ 支持,旧版需降级到
+
事件(见下条)
兜底方案:localStorage + storage 事件兼容老浏览器
当
不可用时(如 Safari localStorage 写入触发
事件实现类似效果:
登录成功后:
监听
注意:
事件不会在触发页自身触发,只通知其他同源标签页,这点与
行为一致
为防污染,建议使用唯一 key 前缀(如
)并定期清理过期项
避免常见陷阱
实际落地中容易忽略的细节:
频道名称必须完全一致且同源
:不同协议(http/https)、端口、子域均视为不同源,无法通信
不要依赖广播顺序或即时性
:消息可能延迟或丢失(尤其页面处于后台或休眠),需配合定时轮询 / WebSocket 心跳做最终一致性保障
登出要全局强制
:收到登出消息后,除清除本地状态外,建议调用
并销毁相关监听器,防止后续误触
敏感信息勿走广播
:token、密码等绝不能放在
中,只传状态类型和必要元数据
BroadcastChannelBroadcastChanneltype"auth:login""auth:logout"timestampuserIdtokenExpiryconst bc = new BroadcastChannel('sso-channel');
bc.postMessage({ type: 'auth:login', userId: 'u123', timestamp: Date.now() });event.sourcefromTabId: window.name || Math.random().toString(36).substr(2, 9)localStorage.getItem('authToken')localStoragestorageBroadcastChannelstoragelocalStorage.setItem('sso:state', JSON.stringify({ type: 'login', timestamp: Date.now() }))window.addEventListener('storage', e => { if (e.key === 'sso:state') { /* 处理 */ } })storageBroadcastChannelsso:v2:bc.close()postMessage