双令牌机制:让认证更安全、体验更流畅

前言

在现代 Web 应用和移动 App 中,用户认证是系统安全的第一道关卡。传统的 Session-Cookie 方案在分布式环境下扩展性受限,而单一的长生命周期 JWT 虽然实现了无状态,却埋下了安全隐患------一旦令牌泄露,攻击者可以在有效期内肆意冒充用户。如何在安全性 与**用户体验****之间找到平衡?双令牌机制(Access Token + Refresh Token)成为业界主流的解决方案。

本文将带你全面了解双令牌的设计思想、核心流程以及背后的实现逻辑,帮助你理解为什么它能兼顾高性能、安全性和用户友好性。

一、什么是双令牌?

双令牌机制将传统的单一长生命周期令牌拆分为两个角色:

1. Access Token(访问令牌)

  • 作用:每次请求业务接口时,客户端携带它来证明用户身份。
  • 特点
    • 有效期短:通常设置为 15 分钟或 30 分钟,降低泄露风险。
    • 无状态:服务端只需验证签名和过期时间,无需查询数据库,性能高。
    • 携带信息:包含用户 ID、角色、权限等关键信息(JWT 的 payload)。

2. Refresh Token(刷新令牌)

  • 作用:不直接访问业务接口,仅在需要获取新 Access Token 时使用。
  • 特点
    • 有效期长:例如 7 天、14 天甚至 30 天,用于维持长期登录状态。
    • 受控状态:服务端通常会存储它的唯一标识(如存入 Redis),便于主动失效。
    • 携带信息:一般只包含用户 ID 和令牌 ID,不包含敏感权限信息。

二、为什么需要双令牌?

安全性更高

  • 单一长生命周期 JWT:若有效期为 30 天,一旦被盗,攻击者可在 30 天内任意操作,且服务端无法主动使其失效(无状态)。
  • 双令牌的改进
    • Access Token 有效期短,泄露后影响范围极小。
    • Refresh Token 仅在刷新接口传输,且可结合服务端白名单控制,一旦发现异常可立即撤销。
    • 服务端能随时将 Refresh Token 加入黑名单,实现强制下线、踢人等功能。

用户体验更佳

  • 若仅使用短期 Access Token,用户会频繁被要求重新登录,体验糟糕。
  • 双令牌机制下,Access Token 过期后,客户端自动用 Refresh Token 在后台换取新令牌,用户完全无感知。
  • 只有在 Refresh Token 真正过期(如 7 天未登录)或主动注销时,才需要重新输入凭证。

兼顾无状态扩展性与会话可控性

  • Access Token 的校验可以完全无状态,适合分布式部署,任意服务节点均可独立完成认证。
  • Refresh Token 在认证中心或网关处维护轻量状态(如 Redis 白名单),实现会话的统一管理(单点登录、踢人下线、设备管理等)。

三、双令牌的实现逻辑

下面我们用纯逻辑描述双令牌机制的完整工作流程。

1. 登录/注册:签发令牌对

  • 用户提供凭证(如手机号+验证码或邮箱+密码)进行登录或注册。
  • 服务端验证凭证通过后,生成一对令牌:
    • Access Token:短期有效,包含用户基本信息和权限。
    • Refresh Token:长期有效,包含用户 ID 和一个唯一的令牌 ID(jti)。
  • 服务端将 Refresh Token 的令牌 ID 存入持久化存储(如 Redis),并设置与 Refresh Token 相同的过期时间。这个存储通常称为"白名单"或"有效令牌集合"。
  • 将这对令牌返回给客户端。

2. 访问业务接口:验证 Access Token

  • 客户端在每次请求业务接口时,在请求头中携带 Access Token(通常是 Authorization: Bearer <token>)。
  • 服务端(或网关)校验 Access Token 的签名、有效期和 issuer 等信息。
  • 校验通过后,从令牌中提取用户信息,继续处理请求;若失败(如过期或签名错误),返回 401 未授权。

3. 令牌刷新:换取新令牌对

  • 当客户端收到 401 响应(或通过定时检查发现 Access Token 即将过期),它会使用 Refresh Token 调用专门的刷新接口。

  • 刷新接口的处理步骤:

    1. 解析 Refresh Token :验证签名和基本格式,确保令牌类型为 refresh
    2. 提取关键信息:从令牌中获取用户 ID 和令牌 ID。
    3. 检查白名单:在 Redis 等存储中查找是否存在该令牌 ID,且状态有效。若不存在,说明 Refresh Token 已被撤销或不存在,拒绝刷新。
    4. 签发新令牌对:生成新的 Access Token 和新的 Refresh Token(注意:Refresh Token 也会轮换,即每次刷新都产生全新的 Refresh Token)。
    5. 更新白名单:将旧的 Refresh Token 从白名单中删除,并将新的 Refresh Token 的令牌 ID 存入白名单,设置相应的过期时间。
    6. 返回新令牌对:客户端用新 Access Token 继续请求业务接口,新 Refresh Token 用于下次刷新。
  • 通过 Refresh Token 轮换,可以确保一个会话中只有一个有效的 Refresh Token 在流转,降低泄露风险。

4. 登出与密码重置:撤销 Refresh Token

  • 主动登出:客户端在登出时,将当前使用的 Refresh Token 发送给服务端。服务端解析出其令牌 ID,从白名单中删除,该 Refresh Token 立即失效。
  • 密码重置:当用户修改密码时,通常意味着所有已登录的设备都应失效。服务端会找到该用户的所有 Refresh Token 记录,批量删除(即全量撤销),从而强制所有客户端重新登录。

5. 安全增强:多维度风控

  • 在刷新令牌时,服务端可额外校验客户端环境(如 IP、User-Agent、设备指纹),若与登录时记录的信息不一致,可视为异常,拒绝刷新并提示用户。
  • 可结合"单点登录"策略,同一用户只允许一个有效的 Refresh Token 存在,新登录将使旧会话失效。

四、设计中的关键考量

1. 为什么需要 Refresh Token 轮换?

每次刷新都生成新的 Refresh Token,可以防止旧的 Refresh Token 被重放。即使攻击者截获了某个 Refresh Token,一旦用户正常刷新或登出,该令牌立即失效,攻击者无法利用它再次刷新。

2. 如何保证传输安全?

所有令牌的传输必须通过 HTTPS 加密,防止中间人窃取。特别是 Refresh Token,应避免在 URL 中传递,仅通过请求头或 Cookie(设置为 HttpOnly)传输。

3. 白名单的粒度与性能

使用 Redis 存储 Refresh Token 的 ID 是最常见的做法,因为它具备自动过期能力和高性能读写。对于大规模系统,可按用户 ID 分片存储,避免单个 key 过大。

4. Access Token 能否携带更多信息?

可以携带常用信息(如昵称、头像)以减少后续查询,但应避免携带敏感数据(如密码哈希、手机号)。Access Token 本身并不加密,内容可以被解码读取。

五、总结

双令牌机制通过将认证令牌拆分为短期访问令牌和长期刷新令牌,在安全性、用户体验和系统扩展性之间实现了完美平衡。它既保留了 JWT 无状态、高性能的优点,又通过服务端可控的刷新令牌引入了会话管理能力,使得强制下线、多端互踢等需求得以轻松实现。

在实际落地时,开发者只需关注以下几个核心环节:

  • 合理设置令牌有效期(短 access + 长 refresh);
  • 设计安全的刷新接口,并实现令牌轮换;
  • 利用 Redis 等存储维护刷新令牌的白名单;
  • 结合 HTTPS 和环境检测增强安全性。

无论是单体应用还是微服务架构,双令牌机制都是一种成熟、可靠的选择。希望本文能帮助你深入理解其原理,并在自己的项目中灵活运用。


相关推荐
jxkejiiii2 小时前
手机无法截屏?可能是手势没设置对(iOS 与 Android 通用排查指南)
人工智能·安全·智能手机
独自破碎E2 小时前
【面试真题拆解】Java文件操作的异常类型与受检_非受检异常
java·面试·职场和发展
q5431470872 小时前
Spring TransactionTemplate 深入解析与高级用法
java·数据库·spring
工一木子2 小时前
String.format 替换踩坑记:从遇坑、读源码到手写实现
java·jdk源码
江沉晚呤时2 小时前
RabbitMQ 延迟队列实战指南:C# 版订单超时与定时任务解决方案
开发语言·后端·ruby
源码师傅2 小时前
2026最新AI短剧创作系统源码 开发语言:PHP+MYSQL 无限SAAS 含图文搭建教程
开发语言·php·ai短剧创作系统源码·短剧创作系统·短剧创作源码
6+h2 小时前
【java IO】IO体系结构 + File类详解
java·数据库·php
海南java第二人2 小时前
Flink状态后端与容错机制深度剖析:TB级状态下的高可用实战
java·spring·flink