4. 令牌刷新流程详解:Refresh Token Grant 流程、刷新请求的认证与授权、新令牌的签发与旧令牌的失效
OIDC(OpenID Connect)协议中的 Refresh Token Grant 是解决 Access Token 短期过期后无感续期问题的核心机制。该流程涉及客户端、授权服务器、资源服务器以及缓存层的协同工作。本节将深入剖析刷新请求的完整生命周期,包括请求认证、新令牌签发以及旧令牌的失效策略。
4.1 Refresh Token Grant 流程全景
Refresh Token Grant 属于 OAuth 2.0 授权码流程的扩展。当 Access Token 过期(通常为 1 小时),客户端可使用长期有效的 Refresh Token 向授权服务器的 Token 端点发起刷新请求,获取一组新的令牌。整个流程不要求用户重新登录,实现了无感续期。
关键前提: Refresh Token 必须在初始授权码交换时由授权服务器签发,且客户端必须安全存储该令牌。Refresh Token 通常具有较长的有效期(如 7 天或 30 天),但可被撤销或轮换。
4.2 刷新请求的认证与授权
授权服务器在处理刷新请求时,必须对客户端和 Refresh Token 进行双重验证。验证失败将直接拒绝请求,并返回 invalid_grant 或 invalid_client 错误。
| 验证维度 | 验证内容 | 失败处理 |
|---|---|---|
| 客户端认证 | 验证 client_id + client_secret(机密客户端)或 client_id(公开客户端) | 返回 401,错误码 invalid_client |
| Refresh Token 有效性 | 验证签名、是否过期、是否已被撤销 | 返回 400,错误码 invalid_grant |
| 绑定关系 | 确认 Refresh Token 与 client_id 匹配,且未超出授权范围 | 返回 400,错误码 invalid_grant |
| 令牌轮换策略 | 若启用轮换,检查 Refresh Token 是否已被使用过 | 撤销所有关联令牌,返回 invalid_grant |
安全警示: 如果授权服务器检测到 Refresh Token 被重复使用(即轮换策略下的重放攻击),必须立即撤销该用户/客户端的所有令牌,并触发安全告警。这是防止令牌泄露后持续滥用的关键防线。
4.3 新令牌的签发与旧令牌的失效
当刷新请求通过所有验证后,授权服务器将执行令牌签发与失效操作。这一过程涉及多个组件的状态变更,是缓存失效问题的重灾区。
4.3.1 新令牌签发流程
- 生成新 Access Token: 使用当前时间作为
iat,设置新的exp(通常为 1 小时),保留原始 scope 和 claims。 - 生成新 Refresh Token(可选): 若启用轮换策略,生成全新的 Refresh Token;若不轮换,则复用旧 Refresh Token。
- 更新持久化存储: 将新令牌的哈希值写入数据库,记录签发时间、客户端 ID、用户 ID。
- 更新缓存层: 将新 Access Token 的映射关系写入 Redis,设置与令牌过期时间一致的 TTL。
- 返回响应: 返回
200 OK,Body 包含access_token、refresh_token、token_type、expires_in。
4.3.2 旧令牌失效策略对比
| 失效策略 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 黑名单模式 | 将旧令牌的 jti 加入 Redis 黑名单,TTL 设为原令牌剩余有效期 |
立即生效,无需等待 TTL 过期 | 增加缓存存储压力,需额外查询黑名单 |
| TTL 自然过期 | 不主动删除,等待旧令牌 TTL 到期后自动失效 | 实现简单,无额外存储开销 | 存在时间窗口(最长 1 小时),旧令牌仍可被使用 |
| 令牌轮换 | 每次刷新签发新 Refresh Token,旧 Refresh Token 立即失效 | 防止 Refresh Token 泄露后的重放攻击 | 增加令牌管理复杂度,需处理并发刷新冲突 |
| 版本号递增 | 在用户/客户端维度维护令牌版本号,旧版本令牌自动失效 | 批量失效,适合强制登出场景 | 需要持久化存储版本号,增加数据库查询 |
生产建议: 推荐采用 令牌轮换 + 黑名单模式 的组合策略。轮换确保 Refresh Token 的一次性使用,黑名单确保旧 Access Token 在刷新后立即失效。同时,在 Redis 中设置合理的 TTL(建议为原令牌剩余有效期),避免黑名单无限膨胀。
4.4 缓存失效的典型故障场景
在令牌刷新过程中,缓存失效是导致认证授权平台故障的最常见原因。以下列出三个高频故障场景及其根因分析:
- 场景一:缓存删除失败导致旧令牌仍可用
刷新请求成功签发新令牌,但 Redis 中旧 Access Token 的映射未被删除。客户端使用旧令牌仍能通过资源服务器的缓存校验,造成新旧令牌同时有效,违反安全策略。 - 场景二:缓存写入延迟导致新令牌无法使用
授权服务器返回新令牌后,Redis 写入操作因网络抖动或主从同步延迟未完成。客户端立即使用新令牌请求资源,资源服务器查询缓存时找不到映射,返回 401。 - 场景三:并发刷新导致令牌状态不一致
客户端在短时间内发起多次刷新请求(如网络重试),授权服务器处理第一次请求后轮换了 Refresh Token,后续请求携带的旧 Refresh Token 被判定为已使用,导致所有令牌被撤销。
诊断要点: 当出现令牌刷新后认证失败时,优先检查 Redis 中
access_token:{jti} 和 refresh_token:{jti} 的键是否存在、TTL 是否正确。同时,查看授权服务器日志中的 grant_type=refresh_token 请求,确认是否触发了令牌轮换冲突。