内容提要
文章介绍OAuth 2.0中accessToken与refreshToken的区别,以及前端实现accessToken无感知刷新的方法:请求前检查本地过期时间,accessToken过期则用refreshToken换取新Token;刷新期间用状态开关防止重复刷新,并挂起未完成请求,待新Token返回后重发;若refreshToken也过期则清空队列并引导用户重新登录。文中以Vue+Axios演示了配置、拦截器、刷新模块及本地存储的实现。
延伸解读
双 Token 机制的安全与体验权衡
文章指出 accessToken 有效期通常很短(如 2~3 小时),频繁重新登录会严重损害用户体验。refreshToken 的引入正是为了在安全与体验之间取得平衡:accessToken 短期有效降低泄露风险,而 refreshToken 允许在用户无感知的情况下续期,直到 refreshToken 也过期才需重新登录。这种设计体现了 OAuth 2.0 凭证式授权中“短凭证+长凭证”的分层思路。
前端主动刷新与请求挂起的实现要点
文章强调刷新判断基于本地存储的过期时间戳,在请求拦截器中比较当前时间与过期时间,仅当 accessToken 过期且非刷新接口时才触发刷新。刷新期间用 isRefreshing 开关防止重复刷新,并将未完成请求存入 requests 队列挂起,待新 Token 返回后重发并清空队列。若刷新失败则清空队列并跳转登录,避免无效请求堆积。
Axios 实例分层与拦截器职责划分
文章将 Axios 配置抽离为 config.ts,避免 create 后 export 导致实例被多处引用而拦截器相互覆盖。instance.ts 负责全局请求/响应拦截(如添加 Token、处理登录失效),index.ts 则侧重业务侧拦截(如刷新逻辑)。这种分层让刷新操作只针对需要鉴权的接口,刷新接口本身不触发刷新,减少了不必要的逻辑耦合。
演示项目的测试与调试建议
文章提供的演示项目默认将 Token 有效期设为 5 秒,并随机模拟 refreshToken 是否过期,方便快速验证刷新、挂起、重新登录等场景。推荐使用本地 Express Server 启动接口服务,可修改 service 文件夹中的返回数据来调整过期时间或刷新成功率。远程 FastMock 因响应慢可能超时,本地方式更利于边测边看代码。
Q&A
OAuth 2.0 中 accessToken 和 refreshToken 有什么区别?
accessToken 是平时请求接口时的用户凭证,有效期较短;refreshToken 是用来刷新用户凭证的刷新凭证,用于在 accessToken 过期时获取新的 accessToken,从而避免用户重新登录。
前端如何实现 accessToken 的无感知刷新?
前端在发起请求前检查本地存储的 accessToken 过期时间,如果已过期,则使用 refreshToken 调用刷新接口获取新的 accessToken,并用新 Token 完成后续请求,整个过程用户无需重新登录。
刷新 Token 时如何防止重复刷新和挂起未完成的请求?
通过一个全局状态开关 isRefreshing 防止重复刷新,刷新期间将未完成的请求存入 requests 数组挂起,待新 Token 返回后重新发起这些请求,并清空队列。
如果 refreshToken 也过期了,前端应该如何处理?
当 refreshToken 过期导致刷新失败时,前端会清空挂起的请求队列,并引导用户重新登录(例如跳转到登录页面)。
在 Vue + Axios 项目中,刷新 Token 的代码通常放在哪些文件里?
通常放在 axios 的拦截器文件中,例如 index.ts 负责业务拦截和刷新逻辑,refreshToken.ts 封装刷新请求,config.ts 和 instance.ts 提供基础配置和实例。
如何判断 accessToken 是否即将过期并触发刷新?
前端从本地存储读取 token_expired_timestamp(过期时间戳),与当前时间戳计算差值,如果差值小于等于 0 且存在本地 Token 记录,则触发刷新。