本文只聚焦 Token 机制,按三个场景说明标准处理流程:
- 登录流程(如何发放与保存 token)
- 日常业务请求(如何带参、后端如何认证)
- 页面刷新与超时处理(正常刷新、过期刷新、失效重登)
一、登录流程
1)目标
登录成功后拿到三类信息并持久化:tokenType、accessToken、refreshToken。
其中 access token 用于业务请求,refresh token 用于续期。
2)前端请求参数
{
"username": "xxx",
"password": "xxx"
}
3)后端返回示例
{
"code": 200,
"msg": "",
"data": {
"tokenType": "Bearer",
"accessToken": "....",
"refreshToken": "....",
"expires": 300000
}
}
4)前端保存规范
- 保存
accessToken为"Bearer " + accessToken - 保存
refreshToken供后续续期使用 - 页面刷新后从持久化存储恢复,避免“刷新即掉线”
二、日常请求后端接口(携带参数 + 后端认证)
1)前端请求拦截器
所有业务请求统一自动注入请求头:
Authorization: Bearer <access_token>
业务接口无需每个页面手工拼 token,统一由拦截器处理。
2)后端认证方式(主流)
- 从 Authorization 头读取 Bearer token
- 使用 IDP 的 JWKS 做签名校验
- 校验 issuer、exp、nbf、aud/azp 等声明
- 校验通过后提取用户身份(sub/username/roles)进入业务层
3)aud/azp 的兼容建议
实战中 access token 可能出现 aud 与 azp 不完全一致,建议:
- 优先匹配预期 audience
- 同时允许按 client_id(azp)做兼容校验
- 所有失败场景输出结构化日志,便于快速定位
三、界面刷新与超时处理(核心)
场景 A:正常刷新(F5)
用户 F5 后,前端从本地恢复 access token 并请求用户信息接口。若 token 仍有效,直接通过,不应弹“重新登录”。
场景 B:access token 过期,但 refresh token 有效
这是最常见场景,主流处理如下:
- 业务请求返回 401(或 token 过期语义)
- 前端不立即登出,先调用
/auth/refresh - refresh 成功后更新本地 token
- 自动重放刚才失败的原请求
- 用户无感知继续使用系统
场景 C:refresh token 也失效
当 refresh 接口返回失败(例如 401),说明会话已彻底过期,此时才执行:
- 清理本地 token
- 弹出“请重新登录”提示
- 跳转登录页
场景 D:并发请求同时 401
需避免“多次同时 refresh”。推荐“单飞刷新 + 队列重放”:
- 第一条 401 触发 refresh
- 其余 401 请求进入等待队列
- refresh 成功后统一重放队列请求
- refresh 失败后统一失败并跳登录
四、推荐的状态机(可直接落地)
已登录
├─ 请求成功 → 保持登录
├─ 请求401
│ ├─ refresh成功 → 更新token → 重放请求 → 保持登录
│ └─ refresh失败 → 清空token → 跳登录页
└─ 主动退出 → 清空token → 跳登录页
五、验收清单
- 登录后连续 F5,不应直接掉线
- access token 过期时自动续期,不中断操作
- refresh token 失效时,才提示重新登录
- 并发请求下只触发一次 refresh,不产生风暴
- Token 失败日志可区分:签名失败 / audience失败 / 已过期 / refresh失败
六、结论
这套方案本质是把“登录态维护”从一次性校验升级为“可续期会话”。
用户体验上,刷新页面与短期过期都应尽量无感;只有在 refresh 也失效时才重新登录。
这就是当前主流 Web 系统处理 token 生命周期的标准实践。