本文目录导读:

这是一个非常经典且重要的系统设计问题,令牌(Token)的过期时间配置,本质上是在安全性和用户体验之间寻找平衡。
没有一个“万能”的固定值,但有一套成熟的配置策略和最佳实践,以下是如何合理配置令牌过期的系统化方案:
核心原则
- 短寿命令牌 + 长效刷新令牌:这是目前最主流的方案。
- 分级保护:不同敏感度的操作使用不同有效期的令牌。
- 绝对过期与滑动过期结合:根据业务场景选择。
最推荐的方案:双 Token 机制
这是解决“体验与安全”矛盾的标准答案。
- Access Token(访问令牌):
- 作用:用于携带在每次API请求的Header中,证明用户身份。
- 过期时间:极短,通常建议 15分钟 到 1小时。
- 理由:即使泄露,攻击者能利用的时间窗口非常小,一旦用户注销或权限变更,最多等待15分钟Access Token就会失效。
- Refresh Token(刷新令牌):
- 作用:仅在Access Token过期时,客户端用它向服务器换取新的Access Token,它不用于直接访问资源。
- 过期时间:较长,通常建议 7天 到 30天,甚至更长(如“记住我”功能可达1年)。
- 理由:提供良好的用户体验,用户无需频繁登录,但它存储在更安全的地方(如客户端的HttpOnly Cookie或安全存储区),且服务器可以将其列入黑名单。
工作流程: 用户登录 -> 获得 Access Token (15分钟) + Refresh Token (7天) 用户访问API -> 使用Access Token -> 服务器验证 -> 成功 15分钟后 -> Access Token过期 -> API返回 401 -> 客户端自动使用Refresh Token去“/refresh”端点 -> 服务器验证Refresh Token有效性 -> 返回新的Access Token (15分钟) -> 客户端继续请求。
配置过期时间的核心考量因素
安全等级(业务敏感度)
- 极高敏感(银行转账、修改密码、删除账号):
- 除了定期登录,每次执行此类操作可能还需要一步验证(如短信验证码、生物识别)。
- Access Token 应设为 5-15分钟。
- 中等敏感(查看个人信息、订单):
- Access Token 设为 1-2小时,Refresh Token 设为 7天。
- 低敏感(浏览公开内容,但需登录):
- 可以接受较长的令牌,例如某些内容平台的阅读者模式,Access Token 可以设为 24小时。
应用类型与用户习惯
- 移动端 App:
- 用户倾向于“一次登录,长期使用”,推荐使用Refresh Token,且可设置滑动过期(Sliding Expiration),用户每次使用App,Refresh Token的过期时间自动延长(比如每次重新计算7天),用户持续使用,令牌永不过期;连续7天未使用,则强制重新登录。绝对过期上限可设为30天。
- Web 端:
- 用户习惯于在浏览器中操作,短时间(如30分钟)的Access Token配合滑动过期效果很好,用户正在操作时计时器重置,离开电脑30分钟后自动退出。
- 后台管理系统:
- 长时间无人值守的风险高,建议采用固定过期,例如4-8小时强制重新登录,配合会话超时,Access Token 1小时。
服务器性能与令牌管理能力
- 无状态令牌(如 JWT):一旦签发,在到期前无法撤销,短有效期是关键风险缓解手段,如果需要立即撤销,需要维护一个黑名单(如Redis),这又会引入状态。
- 有状态令牌(如 Session ID + 数据库):可以随时在服务端删除,过期时间可以设置相对较长(如2小时),因为可以手动终止,但服务器需要查询数据库,性能略差于JWT。
常见业务的推荐配置值(参考)
| 应用场景 | Access Token 有效期 | Refresh Token 有效期 | 备注 |
|---|---|---|---|
| 常规Web App | 15-30 分钟 | 7 天 | 配合滑动过期。 |
| 移动端App | 1-2 小时 | 30-90天 | 用户习惯+设备常联网。 |
| API 服务间调用 | 长期 (如1年) | 无 | 使用客户端凭证模式,令牌通常直接存储在配置文件或密钥管理系统中。 |
| 高安全性(金融、医疗) | 5-10 分钟 | 无(必须每次输入密码或生物验证) | 或者Access Token超短+短生命周期Refresh Token (1小时)。 |
| 三方应用(OAuth2) | 1 小时 | 30天 | 标准OAuth2授权码流程。 |
高级配置策略
-
基于风险的动态过期(Adaptive Token Expiry)
- 使用设备指纹、地理位置、IP地址等风险评分系统。
- 若检测到异常登录(如从异地登录,或使用新设备),自动缩短Access Token的有效期(如从1小时→15分钟),并触发二次验证。
- 若环境安全且是常用设备,可以适当延长。
-
增量刷新(Token Rotation)
- 每次使用Refresh Token换取新Access Token时,服务器同时签发一个新的Refresh Token,并废弃旧的Refresh Token。
- 优点:如果Refresh Token泄露,一旦攻击者使用它刷新了一次,旧Token失效;合法用户下次刷新时会被拒绝,从而知道Token被盗。
- 代价:需要更复杂的服务端状态管理,且可能产生竞争条件。
配置中的常见误区与避坑指南
- ❌ 只配置Access Token,且设置过长(如7天):一旦泄露,攻击者可用一周,这是绝对不安全的。
- ✅ 必须使用Refresh Token + 短Access Token。
- ❌ 把敏感信息(密码、银行卡)放在JWT的Payload里:Payload只做Base64编码,不是加密,任何有令牌的人都可以解码看到。
- ✅ 只在Payload中放必要的标识(如User ID, Role)。
- ❌ 仅仅在客户端(localStorage, sessionStorage)存储Access Token:容易被XSS攻击窃取。
- ✅ 把Refresh Token存入HttpOnly Cookie:增加安全层,Access Token可以放在内存变量中(SPA)或用于非持久性的对象(移动端native存储)。
- ❌ 没有考虑时钟不同步:特别是JWT的
iat(签发时间)和exp(过期时间)依赖于服务器时间,如果客户端或服务器时间偏差大,验证会失败。 - ✅ 在服务器端验证时允许
clockSkew**(通常会理解几秒的偏差,如30秒)。
如何合理配置?
一个安全且体验好的配置遵循如下范式:
- 核心机制:Access Token + Refresh Token。
- 配置参数:
- Access Token:15分钟(敏感操作) 或 1小时(常规操作)。
- Refresh Token:7天(常规) 或 30天(移动端,有“记住我”场景)。
- 存储方式:Access Token 存内存/短期缓存;Refresh Token 存 HttpOnly Cookie 或移动端安全存储。
- 辅助策略:
- 滑动过期:用户活动时自动延长Refresh Token(如移动端)。
- Token Rotation:每次刷新时更换Refresh Token。
- 黑名单:维护一个活跃Blacklist(如Redis),用于立即撤销被盗或已退出的Refresh Token。
通过这套配置,你可以在90%的安全性和优秀的用户体验之间取得良好的平衡,如果是支付、核心资产等场景,可以在此基础上进一步缩短时间和增加验证步骤。