当前位置: 首页 > news >正文

JWT与Session比较

前言

在设想架构时,我面临了一个经典的选择:用户登录后的凭证管理,到底是用传统的 Session,还是用这几年特别火的 JWT? 在做了充分的技术调研和压测后,我最终选择了 JWT。今天这篇文章,我想把当时的思考过程、踩过的坑以及最终的决策逻辑分享出来,希望能给正在做类似选型的你一些参考。

一、先简单回顾一下:Session 和 JWT 分别是怎么工作的?

Session 模式(传统方案)

用户登录 → 服务端生成 SessionId → 存入 Redis/内存 → 返回给客户端 Cookie 后续请求 → Cookie 带 SessionId → 服务端查存储 → 拿到用户信息

特点:服务端存状态,客户端只存一个标识

JWT 模式(无状态方案)

用户登录 → 服务端生成 JWT(内含用户信息+签名) → 返回给客户端 后续请求 → 请求头带 JWT → 服务端验签名 → 直接读取用户信息

特点:服务端无状态,客户端存完整凭证

二、最终让我选择 JWT 的 4 个核心理由

1. 服务无状态 → 水平扩展零成本

我们的项目部署在 Kubernetes 上,Pod 数量会随着流量自动伸缩。

如果使用 Session,我必须维护一个共享的 Session 存储(比如 Redis 集群)。每个请求进来,服务端都要去 Redis 查一次。Pod 越多,Redis 的压力越大,网络开销也越大。

而用 JWT,每个 Pod 都能独立验证 Token,完全不需要任何共享存储。新 Pod 启动就能直接处理请求,扩容就像复制文件一样简单。

// 用 Session 时:每次请求都要查 Redisapp.get('/api/user',async(req,res)=>{constsessionId=req.cookies.sessionId;constuser=awaitredis.get(`session:${sessionId}`);// 网络IO// ...});// 用 JWT 时:本地验签即完成认证app.get('/api/user',async(req,res)=>{consttoken=req.headers.authorization;constuser=jwt.verify(token,SECRET);// 本地计算,无网络IO// ...});

2. 跨端能力天生强大

我们的业务场景涉及:

  • Web 端(浏览器)
  • 微信小程序
  • 移动 App(后续规划)

Session 依赖 Cookie,在小程序和 App 里处理 Cookie 非常别扭(需要手动维护、注意跨域、还要处理移动端的 Cookie 限制)。

JWT 就简单多了:任何端只要能发 HTTP 请求,把 Token 放在 Header 里就行。小程序、App、甚至物联网设备都能统一接入。

3. 减少数据库查询压力

传统 Session 方案里,为了获取用户信息(比如昵称、头像、权限),每个请求可能要:

  1. 根据 SessionId 查 Redis 拿到 userId
  2. 再查数据库或缓存获取用户详情

而 JWT 可以在签发时,直接把非敏感的用户信息编码进去:

consttoken=jwt.sign({userId:123456,nickname:"张三",role:"vip",exp:Math.floor(Date.now()/1000)+7200// 2小时过期},SECRET);

后续请求验证通过后,直接取token.userIdtoken.role使用,数据库零查询。这对高并发场景非常友好。

4. 技术栈无关,微服务友好

我们的后端有 Node.js 的 BFF 层,也有 Java 的业务服务。如果使用 Session,Java 和 Node 要共享同一个 Session 存储,维护一套序列化协议,很麻烦。

JWT 只要共享一个密钥(或 RSA 公钥),任何语言都能验证:

// Java 端验证同一个 TokenStringtoken=request.getHeader("Authorization");Claimsclaims=Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();LonguserId=claims.get("userId",Long.class);

不需要额外的存储中间件,不需要考虑序列化兼容性。

三、但我必须承认:JWT 不是银弹

选 JWT 的同时,我也接受了它的三个代价:

问题1:无法主动失效

用户修改密码后,旧的 JWT 在有效期内依然能用。被封号的用户,只要 Token 没过期,还能继续请求。

我的解决方案

  • 短过期时间(2小时)+ Refresh Token 机制
  • 敏感操作(修改密码、注销)时,客户端主动清除本地 Token
  • 黑名单机制(只针对极端情况,如封号)
// 封号时加入黑名单(Redis)awaitredis.setex(`blacklist:${token}`,tokenExp,'1');// 验证时检查黑名单if(awaitredis.exists(`blacklist:${token}`)){returnres.status(401).send('Token invalidated');}

问题2:Token 体积较大

SessionId 只有几十字节,JWT 轻松几百字节(尤其是存了用户信息后)。

影响:每次请求的 Header 多几百字节,高频 API 会多消耗流量。

权衡:现代网络带宽下,这点开销可以接受。我们做了 Gzip 压缩,实测影响 <5%。

问题3:安全性依赖 HTTPS

JWT 明文存储(即使签名防篡改,但内容 base64 解码后可见),绝对不能存密码等敏感信息。

我的做法

  • 强制 HTTPS
  • 敏感信息(如支付密码)永远不走 JWT 传输
  • JWT 只存 userId、role 这种非敏感标识

四、最终架构:JWT + Refresh Token 双 Token 机制

实际落地的方案是经典的双 Token模式:

Access Token(JWT) - 有效期 2 小时,用于业务 API 调用 Refresh Token(随机字符串) - 有效期 7 天,存在 Redis,用于换取新 Access Token

流程:

  1. 登录成功 → 返回 Access Token + Refresh Token
  2. Access Token 过期 → 用 Refresh Token 换取新 Token
  3. Refresh Token 过期或被盗 → 用户重新登录

这样既享受了 JWT 的无状态便利,又通过 Refresh Token 实现了可控的吊销能力。

五、什么情况我建议你选 Session?

虽然我选了 JWT,但以下场景 Session 可能更合适:

场景原因
单体应用 + 服务端渲染Session 原生支持,简单可靠
需要实时踢人下线的管理系统Session 可随时删除,JWT 很难
用户量不大(<1万并发)Session + Redis 足够,无需折腾
银行、支付等安全敏感系统Session 可控性更强
团队对 JWT 不熟悉避免引入不熟悉的技术

六、写在最后

技术选型没有绝对的对错,只有适不适合。

JWT 用无状态换来了扩展性和跨端能力,代价是放弃了主动失效的便利。如果你的项目需要快速水平扩展、服务多端、追求性能,JWT 是一个非常好的选择。如果你的项目重视实时管控、用户量不大、单体架构,Session 依然简单好用。

我的一条建议:不要为了用 JWT 而用 JWT。先问自己几个问题:

  • 你的服务需要水平扩展吗?
  • 你有多个端(Web/App/小程序)吗?
  • 你能接受 Token 无法主动失效吗?

答案如果偏“是”,JWT 值得一试;如果偏“否”,Session 就挺好。


希望这篇文章对你有帮助。如果你也在做类似选型,欢迎在评论区交流你的思考!

http://www.cnnetsun.cn/news/1682395.html

相关文章:

  • AI人脸隐私卫士问题解决:遇到漏检人脸?调整阈值提升检测覆盖率
  • OpenClaw自动化报告:Qwen3-32B生成周报与数据可视化的整合
  • FPGA实现SRIO高速图像传输方案,设计模式(C++)详解——状态模式(State)(2)。
  • nanobot超轻量级AI助手快速部署指南:内置Qwen3-4B模型实战教程
  • 内容创作者的福音:OFA视觉蕴含模型快速检测图文匹配度
  • BERT文本分割-中文-通用领域实战教程:Gradio前端一键部署
  • Hunyuan-MT-7B部署教程:像素语言传送门在阿里云ACK集群中实现高可用服务编排
  • SEO_快速诊断并改善网站SEO的步骤
  • SEO 与内容营销结合
  • ceph-ansible部署L版ceph 及 通过iscsi 共享rbd 对接xencenter
  • 实战:从零构建基于Live2D 4.0 SDK的博客园网页看板娘
  • Qwen3智能字幕对齐系统PS软件教程视频应用:精准对齐设计步骤讲解与快捷键提示
  • Fun-ASR语音识别系统入门指南:从安装到使用,手把手教学
  • 什么是终端安全防护软件?Trellix 告诉你!
  • 生物信息学新手必看:5分钟搞定GEO优化工具本地部署(含Docker配置)
  • 磁共振成像仿真:从原理到应用的革新实践
  • 为什么Restormer能在图像修复任务上超越CNN?深入拆解它的三个核心设计
  • NLP核心算法全解析:从基础到实战,掌握自然语言处理关键技术
  • 阿里Wan2.1视频生成模型保姆级教程:零基础小白也能轻松上手
  • Wan2.2-I2V-A14B惊艳效果:4K超分后仍保持纹理清晰,无明显AI伪影
  • 一款能预警的智能水质检测仪是怎样炼成的
  • Qwen3-ASR-1.7B效果展示:实测粤语、四川话等22种方言识别惊艳效果
  • 别再手动写SQL过滤了!用若依的@DataScope注解,5分钟搞定部门数据隔离
  • OpenClaw技能市场:5个Qwen3.5-9B实用插件推荐
  • 高效论文降重方案:2026年TOP5平台大类对比与终极选择建议
  • 别再死记公式了!用Python+Matplotlib动画演示轮速计差速模型(附源码)
  • 从光纤通信到超快光学:非线性薛定谔方程仿真在工程研究中的5个典型应用场景
  • 实测LTC3108:用20mV启动的能源管理芯片,为你的TEG温差发电项目供电(附完整电路)
  • USB TO SPI(上海同旺电子)调试器调试MCP4822
  • Splide多轮播嵌套终极指南:复杂布局下的轮播组件最佳实践