在 Web 开发和 API 认证中,Access Token 和 Refresh Token 的组合(通常被称为“双 Token 机制”)是目前平衡安全性与用户体验的主流方案。
1. 基本概念与区别
简单来说,Access Token 是“入场券”,而 Refresh Token 是“换票证”。
| 特性 | Access Token (访问令牌) | Refresh Token (刷新令牌) |
|---|---|---|
| 主要作用 | 用于身份验证,携带它请求受保护的资源。 | 用于获取新的 Access Token。 |
| 有效期 | 短(如 15 分钟 - 2 小时)。 | 长(如 7 天 - 30 天)。 |
| 存储位置 | 通常存放在客户端内存或 localStorage。 | 通常存放在安全性更高的 HttpOnly Cookie 中。 |
| 发送频率 | 高(每次 API 请求都要携带)。 | 低(仅在 Access Token 过期时使用)。 |
| 暴露风险 | 风险较高,因为频繁传输。 | 风险较低,传输频率极低。 |
2. 为什么需要“双 Token”?
如果只使用一个长期的 Access Token,一旦该 Token 被窃取,攻击者将在很长一段时间内拥有该账户的完全访问权,且服务端很难主动使其失效。
双 Token 机制的核心逻辑:
- 安全性: Access Token 设为短期,即使泄露,攻击者的攻击窗口也非常窄。
- 体验感: Refresh Token 设为长期,用户不需要在 Access Token 过期后反复输入账号密码登录,系统会自动静默刷新。
3. 运行流程(双 Token 工作流)
- 登录阶段:
- 用户输入账号密码。
- 服务器验证成功,返回两个 Token:
access_token和refresh_token。
- 正常访问阶段:
- 客户端将
access_token放入 HTTP Header 中(通常是Authorization: Bearer <token>)请求数据。 - 服务器校验 Token 有效,返回数据。
- 客户端将
- Token 过期阶段:
access_token过期,服务器返回401 Unauthorized错误。
- 刷新阶段(自动):
- 客户端拦截到 401 错误,自动将
refresh_token发送到专门的刷新接口(如/auth/refresh)。 - 服务器校验
refresh_token:- 有效: 返回一个新的
access_token。 - 无效/过期: 说明用户长久未操作,返回强制登录错误,清理本地缓存。
- 有效: 返回一个新的
- 客户端拦截到 401 错误,自动将
4. 进阶安全策略:Refresh Token Rotation(刷新令牌轮转)
为了进一步增强安全性,现在常用 Token Rotation 技术:
- 每次使用 Refresh Token 换取新的 Access Token 时,服务器会同时返回一个新的 Refresh Token,并将旧的作废。
- 好处: 如果攻击者窃取了 Refresh Token 并抢先刷新,当合法用户再次刷新时,服务器会发现“旧令牌已被使用”,从而识别出安全威胁,并立即作废该用户所有的 Token 强制重新登录。
5. 开发建议 (前端视角)
- 无感刷新: 在 Axios 等请求库中使用
interceptors(拦截器)。在 Response 拦截器中捕获 401 状态码,挂起当前请求,执行刷新逻辑后再重试。 - 防止并发: 如果页面同时发出多个请求且 Token 过期,需要确保只调用一次刷新接口(利用一个
isRefreshing标志位或 Promise 队列)。
从**计算资源(CPU/内存/数据库)**的角度来看,Refresh Token 的处理过程通常比 Access Token 更消耗资源。
我们可以从以下两个维度来拆解它们的开销:
1. 验证频率 vs 单次消耗
虽然单个 Refresh Token 的处理更重,但因为 Access Token 的调用频率极高,总体的系统负载往往集中在 Access Token 的验证上。
| 维度 | Access Token (验证) | Refresh Token (执行刷新) |
|---|---|---|
| 触发频率 | 极高(几乎每一次 API 调用)。 | 低(仅在 Access Token 过期时,如每小时 1 次)。 |
| 计算复杂度 | 低(通常仅需 CPU 进行解密和签名校验)。 | 高(涉及数据库 I/O、哈希计算、新 Token 生成)。 |
| 资源压力点 | CPU 密集型。 | I/O 密集型(数据库/Redis)。 |
2. 为什么 Refresh Token 更“重”?
在标准的生产环境实现中,Refresh Token 的处理通常包含以下重资源操作:
- 数据库/缓存查询: 为了安全性,Refresh Token 通常不是纯无状态的。服务端需要去数据库(或 Redis)中检查该 Token 是否被加入黑名单、是否已被撤销(Revoked),或者是否匹配用户当前的设备 ID。
- 数据库写入(Token 轮转): 如果开启了 Refresh Token Rotation,每次刷新都要删除旧 Token 并插入新 Token,涉及一次数据库写操作。
- 密码学开销: 需要重新生成两段复杂的随机字符串或 JWT 签名,并可能涉及对数据库中的 Token 进行加盐哈希比对。
3. Access Token 的“轻量”优势
相比之下,Access Token 通常设计为 自包含的 JWT (JSON Web Token):
- 无需查库: 服务器只需要利用内存中的 Secret Key 对 Token 签名进行数学运算(HMAC 或 RSA 校验)。
- 计算极快: 这种校验是在内存中完成的,耗时通常在微秒级别。
总结与优化策略
- 性能瓶颈: 如果你的应用有数百万并发,Access Token 的签名校验(CPU 消耗)会成为主要瓶颈。此时通常会使用分布式网关(如 Kong 或 Nginx 插件)在入口处分担校验压力。
- 数据库压力: 如果用户频繁掉线触发刷新,Refresh Token 的数据库读写会成为瓶颈。这也是为什么开发者通常将 Refresh Token 存储在 Redis 而不是 PostgreSQL/MySQL 中的原因。
简单结论:
- 单次处理: Refresh Token 消耗大(因为要读写数据库)。
- 整体系统负载: Access Token 消耗大(因为验证次数太多)。
在 Access Token(通常是 JWT)的校验中,选择 HMAC 还是 RSA 直接决定了系统的性能消耗、安全性以及架构复杂度。
由于 Access Token 的校验频率极高,理解这两者的计算开销差异至关重要。
1. 核心区别:对称 vs 非对称
| 特性 | HMAC (如 HS256) | RSA (如 RS256) |
|---|---|---|
| 算法类型 | 对称加密(同一密钥)。 | 非对称加密(私钥签发,公钥校验)。 |
| 密钥管理 | 签发者和校验者必须共享同一个 Secret。 | 签发者持有 Private Key,校验者只需 Public Key。 |
| 计算开销 | 极低(仅需一次哈希运算)。 | 较高(涉及大数模幂运算)。 |
| 安全性 | 密钥一旦泄露,攻击者可伪造 Token。 | 公钥泄露无妨,只有持有私钥的中心服务器能签发。 |
2. 计算资源消耗对比
从 CPU 消耗的角度来看,两者存在量级上的差异:
HMAC (对称加密 - 速度王者)
HMAC 校验本质上是执行两次哈希函数(如 SHA-256)。对于现代 CPU 来说,哈希运算有硬件加速,耗时通常在 纳秒 (ns) 或 极低微秒 (μs) 级别。
- 适用场景: 单体架构,或者内部微服务之间高度信任、统一配置中心分发密钥的场景。
RSA (非对称加密 - 安全卫士)
RSA 校验涉及复杂的数学运算(大数模幂)。虽然校验(使用公钥)比签名(使用私钥)快得多,但相比 HMAC,它仍然要慢 10 到 100 倍。
- 适用场景: 跨机构 API(如 Google Auth)、大型微服务架构(各服务只需公钥即可自主校验,无需联系认证中心)。
3. 为什么 RSA 在现代架构中更流行?
尽管 RSA 消耗更多 CPU 资源,但在分布式系统中,它的优势弥补了性能损失:
- 解耦与横向扩展: 认证中心(Auth Service)生成 Token 后,下游的几十个业务服务(Order, User, Payment)只需要持有公钥。即使某个业务服务被黑,黑客也拿不到私钥,无法伪造 Token。
- 安全性提升: 如果使用 HMAC,你必须把唯一的 Secret 分发到所有服务器。泄露风险随着服务器数量线性增长。
4. 性能折中方案:ECDSA
如果你既想要 RSA 的安全性(非对称),又想要 HMAC 的高性能(低消耗),现代开发通常会选择 ECDSA (椭圆曲线数字签名算法),如 ES256。
- 计算开销: 远小于 RSA,接近 HMAC。
- 安全性: 非对称加密。
- 长度: 生成的 Token 比 RSA 更短,节省网络带宽。
总结建议
如果你正在设计系统,可以参考以下逻辑:
- 追求极致性能 / 小型项目: 用 HMAC (HS256)。简单、快,注意保护好 Secret 即可。
- 中大型微服务 / 对安全性敏感: 用 RSA (RS256)。虽然 CPU 消耗稍高,但对于现代服务器来说,这点校验压力通常不是瓶颈。
- 高性能分布式系统: 强烈建议使用 ECDSA (ES256),它是目前性能与安全的最佳平衡点。