别用 JWT 管理用户会话

参考:Stop using JWTs!(samsch)


一句话结论:JWT 不适合用来维持用户登录状态。 它本来就不是为持久会话设计的;真正干这件事的工具,是服务端 Session + Cookie,而且这套方案已经用了几十年。

先把概念对齐。很多人把「Cookie vs JWT」拿来对比,这本身就不对——Cookie 是存储/传输机制,JWT 是带签名的令牌格式,两者不是对立关系。真正该比的是:

  • 无状态 JWT:会话数据直接编码进 Token 里
  • 有状态 JWT:Token 里只放一个 Session ID,数据仍在服务端
  • 传统 Session Cookie:一个(可选签名的)Session ID,数据同样在服务端

本文不是说 JWT 永远不该用,而是:别把它当会话机制。 那样做既不合适,还有安全隐患。

常见误区

「无状态更好扩展」——只有无状态 JWT 在技术上才略沾边,但绝大多数应用根本到不了那个规模。单机多进程用 Redis 存 Session,多机再挂一台 Redis,现有框架都支持得很好。真到了要换方案的时候,全员登出一次就能迁移,不值得为了「未来可能」提前背上 JWT 的坑。

「JWT 更简单、更灵活、更安全」——恰恰相反。框架自带的 Session 开箱即用;灵活度上 Session 本来就能存任意数据;安全上,好的 Session 实现同样会用签名 Cookie,「用了密码学」不等于更安全。把 JWT 塞进 Local Storage 反而更危险——任何能执行 JS 的 XSS 都能把 Token 读走,而 HttpOnly Cookie 天生防这个。

「JWT 自带过期,不用管 Session 清理」——服务端过期同样好做,而且能在过期时清理数据库里的 Session 数据;无状态 JWT 过期前服务端毫无办法。

「用 JWT 就不用 Cookie 同意弹窗」——错。法规管的是持久标识符,跟你怎么存无关。功能性登录态本来就不需要额外同意;追踪分析才需要,换 JWT 也逃不掉。

「放 Local Storage 能防 CSRF」——CSRF 要靠 CSRF Token 防,跟 Session 机制无关。JWT 放 Cookie 一样有 CSRF;放 Local Storage 则强依赖 JS,还引入 XSS 风险。正确的 CSRF 缓解只有一种:CSRF Token

「移动端/禁 Cookie 用户更适合 JWT」——移动浏览器和 HTTP 客户端都支持 Cookie;禁 Cookie 的用户通常也会禁 Local Storage。后端对移动端和 Web 端可以同一套 Session,Cookie 对 HTTP 客户端来说就是普通请求头,每次带上即可。

真正的代价

体积大。 无状态 JWT 把用户信息全塞进 Token,很容易顶破 Cookie 4KB 上限,被迫改用 Local Storage——然后回到上面的安全问题。

无法单独作废。 Session 可以随时在服务端踢掉;无状态 JWT 在过期前永远有效。用户改密码、发现账号被盗、撤销管理员权限——你都没法立刻让旧 Token 失效,只能等它自然过期,或者自己搭一套「黑名单」基础设施,那「无状态」也就名存实亡了。

数据会过期。 Token 里的角色、权限、资料都是签发那一刻的快照。用户刚被降权,手里还攥着写着 admin 的旧 Token,而你又作废不了它。

实现欠打磨。 有状态 JWT 本质上就是 Session Cookie 的劣化版——功能一样,却少了 express-session 这类久经沙场、反复修漏洞的实现。自己撸一套,很容易踩坑。

JWT 规范本身也饱受安全圈质疑:早期甚至允许 alg: none 伪造 Token,整体设计面向的是极短寿命(大约 5 分钟以内)的凭证,不是长登录态。

那 JWT 适合什么?

适合一次性、短时效的授权凭证,而不是持久会话。典型场景:

  • 文件下载:应用服务器验证登录后发一个几分钟有效的下载 Token,无状态的下载服务器验签后直接吐文件
  • 单点登录中转:Google 浏览器里用的是普通 Cookie Session;JWT 只在跨服务传递「刚登录成功」这一下,随后各产品各自建 Session
  • 微服务内部:网关验完 Session 后,用短寿命 Token 在内部服务间传递身份,避免每个服务都查一遍 Session 库——但即便这里,内网 API Key + 明文传用户 ID 往往也够,未必非 JWT 不可

好的 JWT 用法有几个共同点:短命、单次或极少次使用、应用本身仍用 Session 管登录。

该怎么做

直接用框架自带的 Session。对于 Javaer 来说 SpringBoot 封装的非常好,引入几个依赖写几行代码就搞定了,如果想要保存到 Redis 也是引入一个依赖的事情,非常方便!

总结

Cookie 是旧技术,但旧不等于差。安全领域,久经考验、没被打穿,往往比「新且未经充分检验」可靠得多。

Session 和 JWT 可以并存,各干各的——只是别把 JWT 当长期登录凭证。 用户登录这件事,交给 Session 就好。

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
ARTS 0815: 分隔链表、大删除是加活不是减负与协议栈如何一层层拆信封
4
DeepSeek Harness 缓存命中率太惊人了,有时候竟然能到 99%,看鱼皮哥的视频竟然还出现过 100% 😱 https://www.bilibili.com/video/BV1VkgK6NEZS
7
ARTS 0809: 反转链表、Shopify 如何用 MySQL 解决超卖与 AI 时代程序员的价值
5
译文:《SwiftUI 七年:平庸的故事》 SwiftUI 在 2019 年高调发布,本应成为苹果全平台成熟、可量产的 UI 未来。七年过去,到了 2026 年,它仍像一场永不结束的 beta:布局难预期、性能不稳、数据流混乱,还几乎没有可靠的向后兼容,开发者被迫写一堆 shim 和 workaround。 作者用苹果官方教程(甚至是有问题的)以及与 UIKit 的对比说明:SwiftUI 用“看起来方便”换掉了精确的工程控制。更深一层,他认为这反映了苹果从 Cocoa、Aqua、Auto Layout 那种不妥协的工艺,转向“够用就行”的企业文化。 SwiftUI 为何存在 苹果并非单纯想提供更好工具,而是不得不应对竞争:React、React Native、Flutter 让“一套代码多端跑”变得诱人;Mac 上原生应用又日渐被网页和 Electron 吃掉。SwiftUI 要同时拴住原生生态、并降低移植到 Mac 的成本。卖点是:响应式数据流、声明式布局、跨平台复用。 数据流 “单一数据源”听起来很美,实际却是 @State、@Binding、ObservedObject,再到 Observation / @Observable 的不断换代。你很难确定视图会更新几次、为何更新;它该忽略的变化会反应,该关心的变化又可能忽略 - - 像个黑盒。 布局系统 基于尺寸协商的布局在 Keynote 里很合理,做浮动视图、自定义侧边栏时却极度不稳定。官方教程里一个很普通的侧边栏,多年仍有问题。布局脆弱到最后往往只能上 GeometryReader - - 一旦用了,声明式优势就没了,还要手算坐标,而且下一版布局规则一变,数学还得重写。 API 稳定与功能对等 代码里满是 if #available。滚动收起键盘要到 iOS 16;工具栏定制很晚才来;网络图片 AsyncImage 要到 iOS 15,缓存相关 API 到 2026 年 7 月仍在 beta。旧 API 常被换掉(如 NavigationView → NavigationStack),开发者要维护多套实现,等于替苹果做 QA。对比 Android 的 Jetpack Compose 可作为依赖打包回退到旧设备,SwiftUI 做不到“写最新 API、稳定回退”。 性能 在真实对比里,即便做了后台解码等优化,SwiftUI 图片网格滚动仍明显不如 UIKit。若展示一堆 JPEG 都得靠顶级芯片撑,架构本身就有问题。 跨平台神话 苹果说的是“学一次、到处用”,不是“写一次、到处跑”。iOS 上学到的布局很少直接适用 Mac;同一套 view 跨平台实现也不一致。结果常变成:学一次、再学一次、某处能用、处处要调。 哲学转向 最大的问题是“够用就行”:覆盖 90% 用例就算成功,用 velocity 掩盖质量下降。作者列举系统与一线应用中的各种瑕疵,认为这不是偶然,而是苹果主动降低质量门槛 - - 所以即使过了七年,他仍不信任 SwiftUI。 结论 对构建稳定、高性能、可维护系统真正重要的部分,SwiftUI 几乎都有问题。它不是“极差”,而是平庸 - - 用假便利换真精度,要么你花时间给框架打补丁,要么把半成品发出去。作者更宁愿继续用“遗留”的 UIKit / AppKit。 最后小总结: 最让人不能接受的不是“SwiftUI 还有 bug”,而是它把“看起来很快”当成了工程上的完成态。声明式、预览、跨平台,每一项都在秀高级感,可真正写进业务后,你面对的是难预测的重绘、脆弱的布局、层层 #available,以及把兼容和排错外包给业务方的现实。七年够长了,若还靠“框架还年轻”解释,那更像是对标准的侮辱。技术选型从来不只是语法偏好,而是你选的是可预期性、可维护成本,以及对用户体验的态度。平庸的“成功”往往比明显失败更危险 ,你说它能上线、能 demo、能交差,但是却在细节里一点点磨损信任。工具可以换代,但对质量的要求不该跟着一起降级。
4
ARTS 0802: 合并有序链表、AI 时代的技术断层与 TCP 200ms 延迟之谜
5
下载 APP