这是一个关于 OAuth 2.0 / JWT 安全架构的经典问题。答案是:取决于你的安全策略,但推荐每次刷新都重新生成 Refresh Token。
两种策略对比
策略 优点 缺点 适用场景
每次重新生成(推荐) 安全性高,可检测 Token 复用 需要维护更多状态 大多数 Web/App 应用
固定不变 实现简单,用户体验好 泄露后无法撤销,无法检测复用 低安全要求场景
为什么推荐每次刷新都重新生成?
1. 安全检测:Token 复用检测(Token Rotation + Reuse Detection)
这是核心原因。如果攻击者窃取了 Refresh Token,而合法用户也在使用:
- 重新生成策略:服务器发现旧 Refresh Token 被再次使用时,可以立即吊销整个 Token 家族(所有派生的 Access/Refresh Token),因为旧 Token 应该已被替换
- 固定策略:攻击者和合法用户都能无限刷新,你无法区分
2. 限制泄露窗口
如果 Refresh Token 泄露:
- 重新生成:最多泄露 1 个 Access Token 的有效期
- 固定:攻击者可以一直刷新,直到用户主动退出或 Token 过期
3. 符合 OAuth 2.0 最佳实践
[RFC 6819 (OAuth 2.0 Threat Model)](https://datatracker.ietf.org/doc/html/rfc6819) 和 [OAuth 2.1 草案](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10) 都明确推荐 Refresh Token Rotation。
实际实现方案
方案 A:滑动窗口(Sliding Window)— 最常用
用户登录
↓
生成 Refresh Token A(有效期 30 天)
↓
用 A 刷新 → 生成新 Access Token + 新 Refresh Token B(有效期从当前重新计算 30 天)
↓
旧 A 失效,记录 A 的 family_id
↓
用 B 刷新 → 生成新 Access Token + 新 Refresh Token C
关键点:
- 新 Refresh Token 有效期重新计算(不是继承旧 Token 的剩余时间)
- 旧 Refresh Token 立即失效(或给一个极短的宽限期,如 5 秒,防止并发请求失败)
- 所有 Token 属于同一个 family(家族),方便批量吊销
方案 B:固定 Refresh Token,但缩短有效期
如果业务要求简单:
- Refresh Token 有效期设为 7 天(而非 30 天)
- 每次刷新时不重新生成,但更新最后活跃时间
- 超过 7 天不活跃则强制重新登录
方案 C:Refresh Token 家族(Family)+ 宽限期
处理并发刷新的优雅方案:
// 伪代码
func refresh(refreshToken string) {
token, err := db.GetRefreshToken(refreshToken)
if err != nil {
return 401
}
// 检查是否被吊销
if token.Revoked {
// 检测到复用!吊销整个家族
db.RevokeTokenFamily(token.FamilyID)
// 通知用户(可选:发送邮件/推送)
return 401, "Token reuse detected, please re-login"
}
// 生成新 Token 对
newAccess, newRefresh := generateTokens()
// 旧 Token 标记为已使用(宽限期 5 秒)
db.MarkAsUsed(token.ID, gracePeriod=5*time.Second)
// 新 Refresh Token 继承 family
db.SaveRefreshToken(newRefresh, familyID=token.FamilyID)
return newAccess, newRefresh
}
常见误区
误区 纠正
"重新生成 Refresh Token 太频繁,数据库压力大" Refresh Token 存储本身就需要持久化,多一条记录开销极小
"用户同时打开多个标签页,刷新会冲突" 用 Family + 宽限期(5-10 秒)解决,第一个请求生成新 Token,后续请求在宽限期内仍可用旧 Token
"移动端不需要这么严格" 移动端反而更需要,因为设备更容易丢失/被盗
总结
场景 建议
金融/支付类应用 必须每次重新生成 + 复用检测
普通 Web/App 推荐每次重新生成,Family + 5 秒宽限期
内部工具/低安全要求 可以固定,但缩短有效期到 7 天以内
核心原则:Refresh Token 是"长期凭证",它的安全性比 Access Token 更重要。每次刷新时重新生成 Refresh Token,是成本最低、收益最高的安全加固措施。