用户登录成功后,系统需要在后续请求中识别身份。如果只发一个长期有效的 Token,使用方便,但令牌泄露后的风险时间也会变长;如果 Token 有效期很短,用户又会频繁重新登录。
Access Token 与 Refresh Token 的组合,是在访问便利性和风险控制之间做分工:Access Token 用于访问业务接口,生命周期较短;Refresh Token 用于获取新的访问凭证,生命周期较长但使用范围更窄。
两种 Token 各自负责什么
Access Token
- 携带或关联用户身份
- 随业务请求发送
- 有效期较短
- 被网关或服务校验
Refresh Token
- 只用于刷新凭证
- 不应访问普通业务接口
- 有效期较长
- 需要更严格地存储与撤销两个 Token 不能只是在过期时间上不同。服务端还需要能够区分它们的用途,避免 Refresh Token 被当作 Access Token 使用。
基本登录与刷新流程
用户提交登录凭据
-> 认证服务校验
-> 签发 Access Token
-> 签发 Refresh Token
-> 客户端访问业务接口
-> Access Token 到期
-> 客户端提交 Refresh Token
-> 认证服务验证并签发新凭证刷新过程中不需要再次提交密码,但这不代表 Refresh Token 可以无限使用。账号状态、令牌状态和安全策略仍然要重新检查。
Access Token 为什么要短一些
Access Token 会频繁出现在请求中,接触面较大。缩短有效期可以减少泄露后的可用时间。
有效期不能只复制固定数字,需要结合:
- 系统风险等级;
- 用户操作频率;
- 客户端类型;
- 是否有敏感操作;
- 是否支持撤销;
- 异常登录检测能力。
过短会导致频繁刷新,增加认证服务压力;过长则扩大泄露风险。具体时长需要通过实际使用和安全要求调整。
Refresh Token 需要服务端状态
JWT 常被描述为“无状态”,但 Refresh Token 如果完全无法撤销,用户退出、修改密码或账号被禁用后,旧令牌可能仍然可以换取新凭证。
因此我更关注服务端是否能够记录或判断:
- Refresh Token 是否已签发;
- 对应用户和客户端;
- 是否过期;
- 是否已撤销;
- 是否已被替换;
- 最后一次使用时间;
- 账号当前是否允许登录。
可以存储令牌标识或哈希,而不是直接保存完整明文 Token。
刷新时进行轮换
每次刷新只返回新的 Access Token,而继续使用同一个 Refresh Token,能够实现基本续期,但旧刷新凭证长期有效。
更严格的方式是 Refresh Token Rotation:
提交 Refresh Token A
-> 验证 A 有效
-> 将 A 标记为已使用或撤销
-> 签发 Access Token B
-> 签发 Refresh Token B之后再次使用 A,应被拒绝。若 A 在已经使用后又出现,可能意味着令牌被复制,需要根据策略撤销相关会话。
轮换会增加状态管理和并发处理难度。例如客户端同时发起两个刷新请求时,第二个请求可能使用已经失效的旧令牌,因此客户端也要避免并发刷新。
客户端如何避免重复刷新
多个请求同时发现 Access Token 过期时,不应该各自发起刷新。
第一个失败请求
-> 创建刷新任务
其他失败请求
-> 等待同一个刷新任务
刷新成功
-> 更新凭证
-> 重放允许重试的请求重放请求要谨慎。查询请求通常更容易重试,创建、支付或状态变更类请求可能产生重复副作用,需要依赖幂等设计和业务规则。
Token 放在哪里
客户端存储方式需要根据 Web、移动端和威胁模型决定。
Web 场景常见选择包括内存、受保护 Cookie 和浏览器存储。它们各有风险:
- JavaScript 可读存储更容易受到 XSS 影响;
- Cookie 需要正确设置
HttpOnly、Secure和SameSite; - 自动携带 Cookie 时需要考虑 CSRF;
- 内存存储在页面刷新后需要恢复会话。
不能只说某一种方式绝对安全。重点是明确攻击面,并配合 HTTPS、内容安全策略、CSRF 防护和最小有效期。
移动端应使用系统提供的安全存储能力,不把令牌写进普通日志、明文配置或可公开备份区域。
刷新接口要做哪些检查
收到 Refresh Token 后,认证服务至少需要确认:
- 签名或随机令牌是否合法;
- 类型是否为刷新凭证;
- 是否在有效期内;
- 服务端状态是否允许使用;
- 用户是否存在且未被禁用;
- 客户端或会话是否匹配;
- 是否触发轮换或重复使用规则。
验证失败时,不应返回详细到可以帮助攻击者枚举账号或令牌状态的内部信息。
退出登录和修改密码
退出登录不能只删除客户端 Token。如果服务端允许 Refresh Token 继续换取新凭证,旧会话仍可能恢复。
可以在这些场景撤销刷新凭证:
- 用户主动退出;
- 修改密码;
- 账号被禁用;
- 管理员强制下线;
- 检测到令牌重复使用;
- 用户选择退出所有设备。
Access Token 在短有效期内可能仍然有效。若业务要求立即失效,需要增加黑名单、令牌版本或其他服务端校验,但这也会增加每次请求的状态查询成本。
一个脱敏的响应结构
{
"accessToken": "<short-lived-token>",
"refreshToken": "<long-lived-token>",
"tokenType": "Bearer",
"expiresIn": 900
}这只是结构示例,不包含 HAOVP 的真实 Token、有效期和接口响应。公开日志和截图中也不能展示真实令牌。
网关和认证服务如何分工
在微服务架构中,可以让认证服务负责登录、签发、刷新和撤销;网关负责对普通业务请求进行基础 Access Token 校验和身份传递。
认证服务:
登录与凭据校验
Token 签发与刷新
Refresh Token 状态
退出与撤销
网关:
识别受保护路由
校验 Access Token
清理伪造身份头
向下游传递可信身份
业务服务:
校验具体数据和操作权限刷新接口应由认证服务处理,不能让普通业务服务接受 Refresh Token。
Access Token 与 Refresh Token 配合的核心,不是简单准备两个字符串,而是让短期访问、长期续期、轮换、撤销和客户端存储形成完整闭环。Access Token 降低长期暴露风险,Refresh Token 保持会话连续性;真正的安全性来自用途隔离、服务端状态和异常场景处理。