
1. 引言:两张“入场券”的不同命运
想象你去参加一场大型音乐节。入口处有两种入场方式:一种是工作人员给你一张编号卡片(session id),然后在后台系统里记录你的姓名、年龄、vip等级(session 数据)。你每次进出,工作人员只需要核对卡片编号,系统里调出你的信息。另一种方式是发给你一张加密手环(jwt),手环里直接写入了你的姓名、vip等级和有效期,工作人员扫描手环就能验证身份,后台不需要记录任何信息。
第一种方式就像传统的 session,有状态、可控制、但需要后台系统“记住”每个人;第二种方式就像 jwt,无状态、轻量、但一旦发出就难以收回。本文将从最基础的概念讲起,深入对比 session 和 jwt 的机制、优缺点,帮你做出正确的技术选型。
2. 前置知识:为什么需要状态管理?
http 协议是无状态的——服务器不会记住两次请求之间的关系。为了让服务器能认出“你是谁”,我们需要一种机制来维持状态。session 和 jwt 是两种主流解决方案,但它们的实现哲学截然不同。
3. 核心定义
| 概念 | 定义 | 状态性 |
|---|---|---|
| session | 服务端为每个用户创建的会话对象,数据存储在服务器端(内存/redis/数据库),通过唯一的 session id(通常存于 cookie)关联客户端。 | 有状态(服务端存储) |
| jwt | 一种紧凑的、自包含的 json 对象,通过数字签名保证完整性,用于在客户端和服务器间安全传递声明(如用户身份信息),无需服务器存储状态。 | 无状态(客户端存储) |
cookie 的角色:cookie 是载体,而非会话机制本身。session 将 session id 存于 cookie,jwt 也可以存于 cookie(或 localstorage)。
4. 工作机制详解
4.1 session 工作流程

4.2 jwt 工作流程

5. 核心对比表
| 维度 | session | jwt |
|---|---|---|
| 状态性 | 服务端有状态,需集中存储(如 redis) | 服务端无状态,token 自包含 |
| 存储位置 | session id 在 cookie;数据在服务端 | token 存于客户端(cookie / localstorage) |
| 服务器资源 | 占用服务器内存/redis(用户越多资源消耗越大) | 无存储开销,仅验证签名 |
| 安全性 | session id 可设置 httponly 防 xss;需防 csrf | 若存 localstorage 易被 xss 窃取;签名防篡改但内容可解码 |
| 实时吊销 | ✅ 支持(session.invalidate()) | ❌ 困难,需维护黑名单(增加状态) |
| 分布式扩展 | 需共享存储(如 redis 集群) | ✅ 天然支持,无需共享存储 |
| 跨域支持 | 依赖 cookie,需配置 cors 和 withcredentials | ✅ 通过请求头携带,不受同源策略限制 |
| 过期控制 | 基于最后访问时间的空闲超时(如 30 分钟无操作) | 签发时固定过期时间(exp 声明),无法自动延长 |
| 数据大小 | session id 小(通常几十字节) | jwt 大小随 payload 增长(通常几百字节到几kb) |
| 典型载体 | cookie(httponly) | cookie / localstorage / 请求头 |
6. 原理分析:为什么 jwt 是无状态的?
session 的本质是服务端存储数据,客户端只知道一个“钥匙”(session id)。这意味着服务端必须维护一个“钥匙 ↔ 数据”的映射表,因此是有状态的。
jwt 的本质是把用户信息直接写入令牌,通过数字签名保证令牌未被篡改。服务器收到 jwt 后,只需验证签名(无需查询数据库),就能信任其中的内容,因此是无状态的。
jwt 结构(三部分): header.payload.signature 示例:eyjhbgcioijiuzi1niisinr5cci6ikpxvcj9.eyj1c2vyswqiojeymywizxhwijoxnzqzmtu4odawfq.sflkxwrjsmekkf2qt4fwpmejf36pok6yjv_adqssw5c
签名原理:signature = hmacsha256(base64urlencode(header) + "." + base64urlencode(payload), secret)。服务器使用同样的密钥验证签名,确保令牌未被篡改。
7. 安全风险与防护措施
| 机制 | 主要风险 | 防护措施 |
|---|---|---|
| session | xss 窃取 session id;csrf 利用自动携带 | httponly(防 xss)、samesite=strict/lax(防 csrf)、secure(仅 https)、session id 定期刷新 |
| jwt | xss 窃取(若存 localstorage);签名密钥泄露;无法主动吊销 | 存 httponly cookie(防 xss)、短过期时间(如 15 分钟)+ refresh token、强密钥、敏感信息不入 payload |
8. 适用场景与选型建议
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 传统单体 web 应用 | session + cookie | 实现简单,支持实时吊销,用户状态易管理 |
| 前后端分离(spa) | jwt + httponly cookie | 无状态,跨域友好,兼顾安全 |
| 微服务架构 | jwt | 无需共享 session 存储,服务间调用便利 |
| 移动端 / 原生 app | jwt | 不依赖 cookie,通过请求头传递 |
| 第三方开放 api | jwt / oauth2 | 无状态,适合给第三方应用签发令牌 |
| 需要强制踢人 / 实时注销 | session | 服务端可直接删除 session |
| 高并发、需水平扩展 | jwt + redis 黑名单(可选) | 无状态扩展容易,黑名单解决吊销问题 |
9. 常见误区
| 误区 | 正解 |
|---|---|
| “jwt 比 session 更安全” | ❌ 安全性取决于实现。session 有 httponly 护身,jwt 若存 localstorage 反而不安全。 |
| “session 必须用 cookie” | ❌ session id 可通过 url 重写传递,但体验与安全性差,极少使用。 |
| “jwt 可以无限期有效” | ❌ 必须设置短期过期时间,配合 refresh token 机制。 |
| “jwt 的 payload 可以存密码” | ❌ payload 是 base64 编码,可解码,绝对不能存敏感信息。 |
| “用了 jwt 就完全无状态” | ❌ 若要实现吊销,仍需引入黑名单等有状态机制。 |
10. 总结:一张图看懂选型

| 维度 | session | jwt |
|---|---|---|
| 控制力 | ⭐⭐⭐⭐⭐ 强(可实时吊销、审计) | ⭐⭐ 弱(难以吊销) |
| 扩展性 | ⭐⭐ 需共享存储 | ⭐⭐⭐⭐⭐ 天然无状态 |
| 跨域友好 | ⭐⭐ 依赖 cookie 配置 | ⭐⭐⭐⭐⭐ 请求头传递 |
| 实现复杂度 | ⭐⭐ 简单(框架内置) | ⭐⭐⭐ 需管理过期、刷新 |
最终建议:
- ✅ 内部管理后台、传统单体应用 → session
- ✅ 前后端分离、微服务、移动端 api → jwt + 短期过期 + refresh token
- ✅ 高安全场景 → session + redis(有状态)+
httponlycookie - ✅ 追求极简扩展 → jwt(无状态)
没有绝对“更好”的技术,只有“更合适”的选择。理解 session 和 jwt 的本质差异,才能在架构设计时做出正确决策。
到此这篇关于session和jwt的区别是什么以及与cookie相比详解的文章就介绍到这了,更多相关session、jwt与cookie相比内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论