Flutter Web多标签页场景下JWT令牌同步实现方案咨询
嗨,这个多标签页下的JWT令牌同步问题确实挺棘手的,我之前帮好几个做Flutter Web的开发者梳理过类似的场景,给你几个实用的落地思路:
统一存储+跨标签页事件监听
别把access和refresh token分开存了,统一放在localStorage里管理更省心。每个标签页初始化的时候,注册一个window.onStorage事件监听器——当任意一个标签页完成令牌刷新、更新了localStorage里的令牌后,其他所有同源标签页都会收到这个事件。这时候你要做的就是把当前标签页内存里缓存的令牌替换成新的,同时重置自己的刷新定时器(因为新access token的有效期是重新计算的)。加个“互斥锁”杜绝竞态问题
要避免多个标签页同时发起刷新请求,就得在localStorage里加个临时标记,比如token_refresh_in_progress。当某个标签页要触发刷新时,先检查这个标记:- 如果标记已经是
true,说明有其他标签页正在处理刷新,当前标签页直接放弃本次请求,等着通过storage事件同步新令牌就行; - 如果标记是
false,就把它设为true,然后发起刷新请求。成功的话,更新localStorage里的新令牌对,再把标记清掉;要是失败了,也得先清掉标记,然后去读localStorage里有没有新令牌(大概率其他标签页已经刷成功了),没有的话再引导用户登录。
- 如果标记已经是
内存缓存+定时兜底同步
每个标签页可以在内存里存一份access token的副本,发起API请求时直接用内存里的,比每次读localStorage性能好不少。另外,除了依赖storage事件同步,还可以加个短周期的定时器(比如10秒一次),主动把localStorage里的令牌同步到内存,防止极端情况下storage事件没触发的漏网之鱼。处理刷新失败的边界情况
要是某个标签页拿着旧的refresh token去刷新,肯定会被服务器拒绝(因为旧refresh已经被拉黑了)。这时候别直接跳登录,先去读localStorage里的令牌——如果有新的,就更新内存里的令牌、重置定时器,继续正常用;要是localStorage里也没有效令牌了,再引导用户重新授权。
这样一套流程走下来,基本就能解决多标签页下的令牌同步和竞态问题了,我之前在几个Flutter Web项目里这么落地,稳定性还挺靠谱的。
内容来源于stack exchange

