一、核心概念
1. 两个Token作用
- AccessToken 访问令牌
-
- 有效期短:5分钟~30分钟
- 作用:请求业务接口,放在请求头鉴权
- 特点:易过期,泄露影响小
- RefreshToken 刷新令牌
-
- 有效期长:7天~30天
- 作用:专门用来换新AccessToken
- 特点:不参与业务请求,只走刷新接口
2. 设计目的
- 缩短短期凭证寿命,降低被盗用风险
- 实现无感续登,用户不用重复登录
- 服务端可主动拉黑刷新Token,强制下线
二、完整流程(标准流程)
步骤1:用户登录
- 账号密码/三方登录校验通过
- 后端生成:
-
access_token(短期)refresh_token(长期)
- 同时返回过期时间
- 前端存储
-
- AccessToken:内存 / Header(尽量不存本地)
- RefreshToken:HttpOnly Cookie / localStorage(优先Cookie防XSS)
步骤2:正常业务请求
Authorization: Bearer ${access_token}
后端校验签名+是否过期,合法则放行接口。
步骤3:AccessToken过期触发刷新
三种触发时机任选:
- 请求前预判:前端本地判断即将过期,先发刷新
- 响应拦截捕获 :接口返回
401 Token过期,自动走刷新 - 定时轮询:定时主动刷新
步骤4:调用刷新接口
POST /api/auth/refresh
携带:refresh_token
步骤5:后端刷新逻辑
- 校验
refresh_token是否合法、是否黑名单、是否过期 - 合法 → 生成新 AccessToken(部分方案同时换新RefreshToken)
- 返回新令牌给前端
步骤6:前端替换令牌
- 丢掉旧AccessToken
- 写入新AccessToken
- 重试刚才失败的业务请求
- 用户全程无感知
步骤7:RefreshToken过期
直接清空本地令牌,强制跳转登录页
三、后端核心逻辑(JWT为例)
1. 签发规则
Access:exp = 当前 + 15分钟
Refresh:exp = 当前 + 7天
2. 刷新接口规则
- 校验RefreshToken签名
- 查询刷新令牌黑名单(登出/踢人存入)
- 校验通过 → 下发新Access
- 进阶方案:滚动刷新
-
- 每次刷新同时下发新RefreshToken
- 旧RefreshToken加入黑名单作废
- 优点:更安全,防止长期静态刷新Token被盗
3. 登出逻辑
- 前端清空本地所有Token
- 后端把当前RefreshToken加入黑名单
- 即使Token没过期,也无法再刷新
四、前端实现要点(Vue/React/Next.js通用)
1. 存储最优方案
- AccessToken:运行时内存存储,不持久化
- RefreshToken:存入 HttpOnly + Secure Cookie
-
- 彻底防止XSS盗取
- 前端JS无法读取,最安全
2. 拦截器逻辑
- 业务请求401
-
- 判断错误码=令牌过期
- 暂停所有 pending 请求
- 执行刷新Token
- 刷新成功
-
- 替换令牌
- 批量重试暂停的请求
- 刷新失败
-
- 清空登录态 → 跳登录页
3. 防并发刷新BUG(重中之重)
问题 :多个接口同时401,会发起多次刷新请求
解决:
- 定义全局正在刷新锁
- 正在刷新时,后续刷新请求直接排队,不再重复调用刷新接口
五、常见两种模式
模式1 静态刷新Token(简单)
- RefreshToken永久不变,只刷新Access
- 优点:开发简单
- 缺点:Refresh一旦泄露,长期可用
模式2 滚动刷新Token(企业级推荐)
- 每次刷新 → 换新RefreshToken
- 旧Refresh立刻失效拉黑
- 安全性最高,主流后台、SaaS、Web3项目都用这个
六、优缺点总结
优点
- 短期令牌短命,被盗风险极低
- 用户无感自动续期,体验极佳
- 服务端可控下线,权限管控灵活
- 适配移动端、小程序、浏览器全端
缺点
- 前端拦截器逻辑变复杂,要处理排队、重试、锁状态
- 后端需要维护刷新令牌黑名单(Redis最合适)
- 多端登录需做令牌管理
七、一句话总结
双Token机制采用短期AccessToken鉴权业务,长期RefreshToken无感续期;
Access有效期短降低泄露风险,Refresh用于过期换签;
前端通过响应拦截捕获401自动刷新,加状态锁防止并发重复刷新;
后端基于Redis维护刷新令牌黑名单实现登出踢人,支持滚动刷新进一步提升安全性,兼顾安全性与用户体验。
八、最简技术选型搭配
- 令牌格式:JWT
- 黑名单存储:Redis
- 前端存储:Refresh→HttpOnly Cookie,Access→内存
- 过期配置:Access 15min,Refresh 7d
- 刷新策略:滚动刷新