3. Token 生命周期管理:Access Token 与 Refresh Token 的定义、作用、过期策略
好,咱们来聊聊 Token 生命周期管理。说实话,这是整个身份校验方案里最容易出问题的地方。我见过不少项目,Access Token 设个 7 天过期,结果泄露了,整个系统跟没穿裤子一样。也见过 Refresh Token 设计得太复杂,用户频繁被踢下线,体验极差。
说白了,Token 生命周期管理就是解决一个问题:如何在安全性和用户体验之间找到平衡点。我个人习惯把这个问题拆成三个部分来理解:Access Token 是什么、Refresh Token 是什么、以及它们各自的过期策略怎么定。
3.1 Access Token:短命的通行证
Access Token,你可以把它想象成一张酒店房卡。你拿着它,就能开门、进健身房、用早餐。但问题是,这张房卡如果丢了,别人捡到也能干同样的事。
定义与作用
Access Token 是一个短期有效的凭证,客户端每次请求资源时都要带上它。服务器验证通过后,才会返回数据。它的核心作用就两个:
- 身份认证:证明“我是谁”
- 授权访问:证明“我能干什么”
过期策略
这里有个关键点:Access Token 必须短命。为什么?因为它在网络中传输频繁,被截获的风险最高。
| 场景 | 推荐过期时间 | 说明 |
|---|---|---|
| Web 应用 | 15-30 分钟 | 配合 HttpOnly Cookie,安全性较高 |
| 移动端 App | 1-2 小时 | 网络环境相对可控,可适当放宽 |
| 高安全场景(金融、医疗) | 5-10 分钟 | 宁可频繁刷新,也不能泄露 |
| 内部系统 | 2-4 小时 | 内网环境,风险较低 |
3.2 Refresh Token:长命的保险箱钥匙
Refresh Token 就不一样了。它是一把保险箱钥匙,平时不用,只有在你需要换新房卡的时候才拿出来用一次。
定义与作用
Refresh Token 是一个长期有效的凭证,专门用来获取新的 Access Token。它不直接访问资源,所以即使泄露,攻击者也只能用它来刷新 Token,而不能直接获取数据。
它的核心作用:
- 延长会话:用户不需要频繁登录
- 降低风险:即使 Access Token 泄露,攻击者也只能在短时间内作恶
- 支持离线刷新:移动端 App 可以在后台静默刷新
过期策略
Refresh Token 的过期时间要长得多,但也不是越长越好。
| 场景 | 推荐过期时间 | 说明 |
|---|---|---|
| Web 应用 | 7-14 天 | 配合滑动过期策略 |
| 移动端 App | 30-90 天 | 用户习惯长时间不退出 |
| 高安全场景 | 1-3 天 | 频繁验证用户身份 |
| 记住我功能 | 30 天 | 需要用户主动勾选 |
3.3 核心流程:Access Token 与 Refresh Token 的协作
这两个 Token 是怎么配合工作的?我画了一张图,你看完就明白了。
流程其实很简单:
- 用户登录,服务器返回 Access Token 和 Refresh Token
- 客户端用 Access Token 请求资源
- Access Token 过期后,客户端用 Refresh Token 去换新的 Access Token
- 服务器验证 Refresh Token 有效,返回新的 Access Token
- 客户端用新 Token 继续请求资源
3.4 滑动过期策略:让用户体验更丝滑
嗯,这里要重点说一下滑动过期策略。你想想看,如果 Refresh Token 固定 7 天过期,用户在第 6 天登录,第 7 天还在用,结果突然被踢下线了。这体验多糟糕?
什么是滑动过期?
滑动过期就是:每次用户刷新 Token 时,Refresh Token 的过期时间自动延长。比如用户在第 6 天刷新了,那 Refresh Token 的过期时间就从第 7 天延长到第 13 天。
核心逻辑:
// 伪代码示例
function refreshToken(oldRefreshToken) {
// 验证旧 Refresh Token
if (!isValid(oldRefreshToken)) {
return error("Token 无效");
}
// 生成新的 Access Token
const newAccessToken = generateAccessToken(userId);
// 滑动过期:重新计算过期时间
const newRefreshToken = generateRefreshToken(userId, {
expiresIn: 7 * 24 * 60 * 60 * 1000 // 从当前时间开始,再延长 7 天
});
return { accessToken: newAccessToken, refreshToken: newRefreshToken };
}
3.5 避坑指南:我踩过的那些坑
做 Token 生命周期管理,有几个坑我是一定要提醒你的:
- Refresh Token 轮换:每次刷新时,旧的 Refresh Token 必须立即失效。我曾经见过一个系统,刷新后旧的 Refresh Token 还能用,结果攻击者拿着偷来的 Token 反复刷新,生生不息。
- 并发刷新问题:如果客户端同时发起多个请求,每个请求都发现 Access Token 过期了,然后同时去刷新。这时候怎么办?我的做法是:加一个锁,只允许一个刷新请求执行,其他的等待结果。
- Token 撤销:用户修改密码或账号被盗后,必须能立即撤销所有 Token。我习惯在 Redis 里维护一个黑名单,每次验证 Token 时先查一下黑名单。
3.6 总结:记住这三条原则
好了,关于 Token 生命周期管理,你只要记住这三条原则:
- Access Token 要短命:15 分钟到 1 小时,视场景而定
- Refresh Token 要长命但有限:7 天到 30 天,配合滑动过期
- 轮换和撤销不能少:每次刷新换新 Token,随时能撤销
做到这三点,你的身份校验方案就基本稳了。剩下的就是根据业务场景微调过期时间,这个需要你在实际项目中慢慢摸索。