很多人刚接触 JWT 认证时都会有一个疑惑:如果 access token 短命是为了安全,那 refresh token 长命不是又把安全性抵消了吗?难道因为 refresh token 只存在 HttpOnly cookie 里就没事了?这个问题的答案,需要从“这套方案到底想解决什么问题”说起。
短命 Access Token 不是用来“防偷”的,而是用来缩短破坏窗口
access token 的主要价值,是让服务端可以快速验证请求,而不必每个请求都去认证服务查一次 session。它被签名过,拿到 token 的一方可以信任其内容,然后赋予对应的权限。
但正因为 token 会随着每个请求到处发送,它比 refresh token 更容易暴露。一旦被拦截,攻击者就能在有效期内使用它。所以把它做短命,是为了把“被偷后的可用时间”尽量压缩。注意,这并不是说可以忽略传输安全,HTTPS/TLS 仍然是底线。
Refresh Token 的安全感来自“不常出现”和“可撤销”
refresh token 不会跟着每个 API 请求走,它只在换取新 access token 时使用,通常会被限制在类似 /auth/refresh 的接口里。这样一来,即便某个业务接口失守,攻击者能拿到的也只是 access token,而不是长期有效的 refresh token。
另一个关键点是存储方式。很多人默认 access token 放 localStorage,refresh token 放 HttpOnly cookie,这样 JavaScript 读不到 refresh token,XSS 也就偷不走。但注意,两者其实都可以用 HttpOnly cookie 承载,区别在于 refresh token 需要被服务端追踪,以便支持吊销。
这套方案的真正出发点是性能,尤其是 SOA / 微服务
为什么不用一个长命 token,而是拆成两个?核心原因是性能。在 session 方案里,每次请求都要验证 session 是否有效,这在单体应用里不是问题,但在服务治理(SOA)或微服务环境下,每个服务都需要确认用户身份,每个请求都去认证服务查一次,认证服务就会变成瓶颈,甚至单点故障。
access token 是“热路径”:应用服务器自己校验签名和权限,不依赖认证服务。而 refresh token 是“冷路径”:每几分钟才去认证服务换一次新 token,这样既不会频繁打扰认证服务,又保留了吊销能力。
如果你的应用是单体架构,就不太需要这套复杂度,用 session 反而更直接。这是很多开发者的共识。
容易踩的误区
- 误区一:以为 access token 短命是为了“不让别人偷”。实际上它只是缩短了被偷后的有效时间,真正的安全前提是 HTTPS 和正确的存储。
- 误区二:以为 refresh token 天生比 access token 更安全。它的优势来自“不随请求发送”和“服务端可追踪”,而不是它本身的算法更高级。
- 误区三:以为 access token 和 refresh token 必须用不同的存储方案。两者都可以是 HttpOnly cookie,区别在于生命周期和撤销能力。
如果要做选择
先问自己:是不是真的需要在多个服务之间共享一份可信身份?如果是,access token + refresh token 的分离是有价值的;如果只是单体应用,session 可能更简单可靠。使用 refresh token 时,务必把它当作 session 来管理:设置合理的过期时间,提供吊销接口,并且限制它只能访问认证端点。