JWT和Session基础
用户登录之后,服务器怎么「记住」他是谁?这个问题看似简单,却是所有 Web 应用用户系统的基石。选错认证方案,轻则用户体验糟糕(频繁掉登录),重则安全漏洞百出(会话劫持、Token 泄露)。本文深入拆解 Session 和 JWT 两种主流认证机制的原理、差异与适用场景,帮助你在实际项目中做出合理选择。
一、为什么需要会话管理
HTTP 协议本身是无状态的——每一次请求对服务器来说都是独立的,它不会自动记住「上一次请求来自谁」。但几乎所有 Web 应用都需要在多个请求之间维持用户的登录状态:你登录了邮箱,浏览收件箱、打开邮件、撰写回复,这些请求之间服务器必须知道「这些都是你」。
解决这个问题的两大主流方案就是 Session 和 JWT。它们的根本区别在于:状态信息存放在哪里。Session 把状态存在服务器端,JWT 把状态存在客户端。
二、Session 机制原理
2.1 核心流程
Session 认证的过程可以用四个步骤概括:
- 用户提交凭证:用户通过登录表单提交用户名和密码。
- 服务器验证并创建 Session:服务器验证凭证通过后,在服务端存储一份会话数据(包含用户 ID、角色、登录时间等),并生成一个唯一的 Session ID。
- 返回 Session ID 给客户端:服务器通过 HTTP 响应头的
Set-Cookie字段,将 Session ID 写入浏览器的 Cookie。 - 后续请求自动携带:浏览器在后续每次请求中自动带上这个 Cookie,服务器根据 Session ID 查找对应的会话数据,从而识别用户身份。
2.2 Session ID 的存储方式
Session ID 需要通过某种方式在客户端和服务器之间传递。最常见的载体是 Cookie——浏览器会自动在每个请求中携带对应域名下的 Cookie,开发者无需手动处理。
除了 Cookie,Session ID 也可以通过 URL 参数传递(例如 ?sessionId=abc123),但这种方式存在安全风险(URL 会被记录到浏览器历史、服务器日志中),现代应用已经很少使用。
2.3 服务端的 Session 存储
Session 数据需要存储在服务端的某个地方。常见的存储方案包括:
- 进程内存:最简单的方案,直接存在应用服务器的内存中。单机开发环境够用,但分布式部署时不同服务器之间的 Session 无法共享。
- Redis / Memcached:将 Session 存入集中式的缓存服务,多台应用服务器共享同一份 Session 数据。这是生产环境中最常见的做法。
- 数据库:将 Session 存入关系型数据库或 NoSQL 数据库。适合需要持久化 Session 的场景,但性能不如 Redis。
三、JWT 机制原理
3.1 什么是 JWT
JWT(JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传输声明信息。它的核心特点是自包含——Token 本身就携带了所有必要的用户信息,服务器不需要额外查询存储。
3.2 JWT 的结构
一个 JWT 由三部分组成,用 . 连接:xxxxx.yyyyy.zzzzz。每一部分都经过 Base64URL 编码。
| 部分 | 内容 | 说明 |
|---|---|---|
| Header | {"alg": "HS256", "typ": "JWT"} | 声明 Token 类型和签名算法 |
| Payload | {"sub": "1234567890", "name": "John Doe", "iat": 1516239022} | 携带声明数据(用户信息、过期时间等) |
| Signature | HMACSHA256(base64Url(header) + "." + base64Url(payload), secret) | 用于验证 Token 完整性,防止篡改 |
其中,Payload 里常见的标准声明(Claims)包括:
sub(Subject):Token 的主题,通常是用户 IDiss(Issuer):签发者exp(Expiration Time):过期时间iat(Issued At):签发时间aud(Audience):受众
需要注意的是,Payload 部分只是 Base64URL 编码,并非加密。任何人都可以解码看到里面的内容,所以绝对不要把密码等敏感信息放进 Payload。
3.3 核心流程
JWT 认证的关键在于签名验证——服务器通过密钥验证 Token 是否被篡改,无需查询任何存储。
注意这里的关键区别:服务器不需要查询数据库或 Redis,只需要用本地密钥做一次签名验证。这就是 JWT「无状态」的含义。
3.4 签名算法
JWT 支持多种签名算法,主要分为两类:
- 对称算法(如 HS256):签发和验证使用同一个密钥。适合单体应用,简单高效。
- 非对称算法(如 RS256):签发用私钥,验证用公钥。适合微服务和跨服务场景——签发服务持有私钥,各个消费服务只需要公钥即可验证,不需要共享密钥。
四、Session vs JWT 对比
4.1 核心维度对比
| 维度 | Session | JWT |
|---|---|---|
| 状态存储 | 服务端(内存、Redis、数据库) | 客户端(Cookie、LocalStorage) |
| 可扩展性 | 需要共享存储,分布式部署复杂度较高 | 天然无状态,水平扩展简单 |
| 服务器开销 | 每个活跃用户占用一份存储 | 无存储开销,只消耗签名验证的 CPU |
| Token 大小 | Session ID 通常很短(几十字节) | JWT 较长(通常几百字节到几 KB) |
| 主动撤销 | 直接删除服务端 Session 即可立即失效 | 无法直接撤销,需引入黑名单或等待过期 |
| 跨域支持 | Cookie 方案跨域处理复杂 | 通过 HTTP Header 传递,跨域方便 |
| 移动端适配 | 依赖 Cookie 机制,移动端需额外处理 | 直接存储在客户端,APP 使用更方便 |
| 实时权限变更 | 下次请求立即生效(查服务端数据) | 需要等 Token 过期或引入额外机制 |
4.2 安全模型对比
| 安全威胁 | Session 的风险 | JWT 的风险 |
|---|---|---|
| XSS(跨站脚本攻击) | Session ID 存在 HttpOnly Cookie 中时风险较低 | Token 存在 LocalStorage 中时,XSS 可直接窃取 |
| CSRF(跨站请求伪造) | Cookie 方案天然面临 CSRF 风险,需加 SameSite 或 CSRF Token | 使用 Authorization Header 传递时不受 CSRF 影响 |
| Token 泄露 | Session ID 泄露后攻击者可冒充用户 | JWT 泄露后在过期前持续有效,且无法服务端撤销 |
| 中间人攻击 | 必须使用 HTTPS 保护 | 必须使用 HTTPS 保护 |
| 会话固定攻击 | 登录前后需重新生成 Session ID | 不适用(每次登录签发新 Token) |
五、如何选择
5.1 选择决策矩阵
| 项目特征 | 推荐方案 | 原因 |
|---|---|---|
| 小型单体应用、用户量有限 | Session | 实现简单,运维成本低 |
| 分布式 / 微服务架构 | JWT | 无状态,不需要共享 Session 存储 |
| 需要跨域认证(多子域名、第三方调用) | JWT | HTTP Header 传递,跨域无障碍 |
| 移动端 APP + Web 共用 | JWT | 一套 Token 机制适配多端 |
| 需要实时踢人下线、权限即时生效 | Session | 服务端直接删除 Session 即可 |
| 高安全要求(金融、政务) | Session(或 JWT + 短过期 + 刷新) | 可控性强,出问题可立即切断 |
| SPA(单页应用) | JWT 或 Session + BFF 模式 | 取决于是否需要跨域和微服务集成 |
5.2 不是非此即彼
实际工程中,很多项目会混合使用两种方案。例如:
- JWT + 服务端黑名单:用 JWT 做无状态认证,同时在服务端维护一个已撤销 Token 的黑名单(通常存 Redis,设置与 Token 剩余有效期相同的 TTL)。兼顾了 JWT 的扩展性和 Session 的可撤销性。
- JWT + Refresh Token:Access Token 使用短过期时间(如 15 分钟),配合一个长期有效的 Refresh Token(存在服务端或 HttpOnly Cookie 中)。Access Token 过期后用 Refresh Token 换取新的。
- Session + BFF(Backend For Frontend):前端用 Session 管理登录态,BFF 层负责将 Session 转换为 JWT 调用后端微服务。
六、安全考虑
6.1 Session 安全要点
- 设置 Cookie 安全属性:
HttpOnly防止 JavaScript 读取、Secure限制只在 HTTPS 下传输、SameSite=Strict或SameSite=Lax防止 CSRF。 - 登录后重新生成 Session ID:防止会话固定攻击(Session Fixation)。
- 设置合理的过期时间:空闲超时(如 30 分钟无操作自动过期)和绝对超时(如 24 小时强制重新登录)。
- 使用 Redis 集中存储时,确保 Redis 实例本身的访问安全和网络隔离。
6.2 JWT 安全要点
- 不要存放敏感信息:Payload 只是编码,不是加密。密码、身份证号等绝对不能放进 JWT。
- 设置合理的过期时间:JWT 一旦签发,在过期前一直有效。过期时间越短,泄露后的风险窗口越小。
- Token 存储位置:存在 LocalStorage 中容易受 XSS 攻击;存在 HttpOnly Cookie 中可以规避这个问题,但需要处理 CSRF。
- 使用强密钥:对称算法的密钥至少 256 位,非对称算法的私钥妥善保管。
- 验证所有字段:除了签名,还要验证
iss(签发者)、aud(受众)、exp(过期时间)等声明。
6.3 通用安全原则
无论使用 Session 还是 JWT,以下原则都适用:
- 强制 HTTPS:所有认证相关的通信必须走 HTTPS,防止中间人攻击。
- 限制登录尝试频率:防止暴力破解。
- 记录安全日志:登录、登出、Token 刷新、异常请求等关键事件都需要记录。
- 遵循 OWASP 指南:OWASP Session Management Cheat Sheet 和 NIST SP 800-63B 是业界公认的安全基线。
七、实际案例
案例 1:单体电商后台管理系统
某出海电商的后台管理系统,技术栈为 Next.js + Express,用户量约 500 个运营人员。系统只需要支持 Web 端,不需要跨域调用。
方案选择:Session + Redis
理由:单体应用、用户量可控、不需要跨域、需要即时踢人下线能力(员工离职或权限变更)。Session 方案实现简单,通过 Redis 存储 Session 数据,运维成本也低。运营人员登录后台后,Session ID 通过 HttpOnly + Secure + SameSite=Strict 的 Cookie 传递,安全性有保障。
案例 2:AI SaaS 平台的 API 服务
某 AI 产品出海项目提供 SaaS 服务,前端是 SPA,后端是多个微服务(用户服务、计费服务、AI 调用服务),同时提供 OpenAPI 供第三方开发者调用。
方案选择:JWT(RS256)+ Refresh Token
理由:微服务架构下,Session 共享的复杂度太高。JWT 的无状态特性让每个微服务可以独立验证 Token,不需要互相通信。使用 RS256 非对称签名,由认证服务持有私钥签发 Token,其他服务只需要公钥验证。SPA 前端将 Access Token 存在内存中(变量),Refresh Token 存在 HttpOnly Cookie 中,兼顾安全性和跨域能力。Access Token 有效期 15 分钟,Refresh Token 有效期 7 天。
八、实施检查清单
无论选择哪种方案,以下检查项都值得逐条确认:
Session 方案检查清单
- Cookie 设置了
HttpOnly、Secure、SameSite属性 - 用户登录后重新生成了 Session ID
- Session 设置了合理的过期时间(空闲超时 + 绝对超时)
- 分布式部署时使用了集中式 Session 存储(如 Redis)
- 登出时正确清除了服务端 Session 数据
- 敏感操作(修改密码、支付)要求二次验证
JWT 方案检查清单
- Payload 中没有包含密码等敏感信息
- 使用了足够强的签名密钥(对称 ≥ 256 位)
- 设置了合理的过期时间(建议 15 分钟 ~ 1 小时)
- 服务端验证了
iss、aud、exp等标准声明 - Token 存储位置考虑了 XSS 风险(LocalStorage vs HttpOnly Cookie)
- 实现了 Token 刷新机制(Refresh Token 或滑动过期)
- 有 Token 撤销方案(黑名单或短过期 + 刷新)
- 所有认证通信强制走 HTTPS
九、小结
Session 和 JWT 不是「谁更好」的关系,而是在不同约束条件下的权衡取舍。Session 把状态留在服务器,换来的是即时可控性和简单的安全模型;JWT 把状态交给客户端,换来的是无状态的扩展性和跨平台的灵活性。
对于 AI 产品出海项目,如果你的初期是单体架构、用户量有限,Session 是稳妥的起步选择;如果从第一天就规划了微服务、多端、开放 API,JWT 会帮你减少很多架构上的麻烦。理解两者的原理和边界,才能在实际场景中做出适合你的选择。
参考资料
- RFC 7519 - JSON Web Token (JWT) — IETF 官方 JWT 规范
- JWT.io - Introduction — JWT 入门指南与在线调试工具
- Auth0 - JSON Web Token Structure — JWT 结构详解
- OWASP - Session Management Cheat Sheet — OWASP 会话管理安全速查表
- NIST SP 800-63B - Session Management — NIST 会话管理官方指南
- LoginRadius - JWT vs Session Authentication: Real Scaling Differences — JWT 与 Session 的扩展性对比分析
- Logto Blog - JWT vs Session Authentication — 认证方案选型实践指南