JWT
JWT(JSON Web Token) 是基于 RFC 7519 标准的轻量级、自包含的开放数据传输标准,主要用于网络应用中的身份认证与安全信息交换。其核心优势是无状态、自包含、可跨域、易扩展,特别适合前后端分离、微服务与分布式架构。
一、JWT 结构
JWT 是一段由 . 分隔的 Base64URL 编码字符串,格式固定为三部分:
Header.Payload.Signature
示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
1. Header(头部)
-
作用:描述令牌元数据(类型、签名算法)
-
格式:JSON → Base64URL 编码
-
典型字段
alg:签名算法(如HS256、RS256、ES256)typ:固定为JWT
示例:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload(载荷 / 声明)
- 作用:存放实际业务数据(用户 ID、权限、过期时间等)
- 格式:JSON → Base64URL 编码
- ⚠️ 注意:仅编码、未加密,严禁存放密码、手机号等敏感明文
三类声明(Claims) :
-
标准注册声明(推荐)
iss:签发者(如服务域名)sub:主题(通常是用户 ID)aud:受众(接收方)exp:过期时间(Unix 时间戳,必须大于签发时间)nbf:在此时间前不可用iat:签发时间jti:JWT ID(唯一标识,防重放)
-
公共声明
- 自定义公开字段(如
name,role,scope)
- 自定义公开字段(如
-
私有声明
- 通信双方约定的私有字段
示例:
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622
}
3. Signature(签名)
- 作用:验证 Header+Payload 未被篡改、确保发送方真实可信
- 生成公式:
Signature = HMAC-SHA256( Base64URL(Header) + "." + Base64URL(Payload), 密钥/私钥 )
-
常见算法
- HS256(对称):单密钥签名 + 验证,简单高效
- RS256(非对称):私钥签名、公钥验证,更安全
- ES256(椭圆曲线):短密钥、高安全性
二、JWT 认证流程(典型场景)
- 用户登录:客户端提交用户名 / 密码
- 服务端验证:验证账号密码 → 生成 JWT
- 返回令牌:服务端将 JWT 发给客户端
- 客户端存储:存在 localStorage/sessionStorage/cookie
- 后续请求:
- 放在 HTTP Header:
Authorization: Bearer <token> - 或 POST 参数、URL 参数
- 放在 HTTP Header:
- 服务端验证
- 拆分 Header.Payload.Signature
- 用相同算法 / 密钥重新计算签名
- 对比签名是否一致、检查
exp是否过期
- 通过则处理请求
三、核心特点
- 自包含:令牌自带所有必要信息,无需查会话库
- 无状态:服务端不存会话状态,水平扩展极方便
- 跨域 / 跨服务:可在多域名、微服务间传递
- 紧凑高效:体积小,可在 URL/Header/POST 中传输
- 语言无关:支持几乎所有主流语言
四、优缺点
✅ 优点
- 分布式 / 微服务友好(无状态、易共享)
- 减少数据库 / Redis 查询(自包含)
- 跨域、跨平台、跨技术栈通用
- 易于实现单点登录(SSO)
❌ 缺点
- 令牌不可主动作废(除非引入黑名单 / Redis)
- Payload 仅编码不加密,敏感信息不能明文放
- 体积比 SessionID 大,占用少量更多带宽
- 需严格控制过期时间(
exp)
五、常见应用场景
- 前后端分离项目(Vue/React/ 小程序)身份认证
- API 接口授权(开放平台、第三方调用)
- 微服务内部鉴权、网关认证
- 单点登录(SSO)
- 一次性短时效授权(密码重置、邮箱验证)
六、安全最佳实践
- 必须使用 HTTPS(防止中间人截获 Token)
- 短过期时间(access_token:15~60 分钟)
- 双令牌机制
- Access Token:短时效,用于业务请求
- Refresh Token:较长时效,仅用于刷新 Access Token
- 敏感信息不放 Payload(如密码、身份证)
- 密钥高强度、定期轮换
- 关键操作二次验证(支付、改密)
- 必要时实现令牌黑名单(登出 / 改密后加入黑名单)
七、JWT vs Session-Cookie(对比)
表格
| 特性 | JWT | Session-Cookie |
|---|---|---|
| 状态 | 无状态(服务端不存) | 有状态(服务端存 Session) |
| 分布式 | 天然支持 | 需共享 Session(Redis) |
| 跨域 | 良好 | 受 Cookie 跨域限制 |
| 存储位置 | 客户端(localStorage/cookie) | 服务端(内存 / Redis) |
| 主动失效 | 难(需黑名单) | 易(服务端直接删除) |
| 带宽 | 较大(Token 较长) | 小(仅 SessionID) |
总结
JWT 是现代无状态认证的主流方案,以 Header.Payload.Signature 结构实现安全、自包含、可跨域的身份与授权传递。核心是签名防篡改、自包含、无状态。使用时务必:HTTPS + 短过期 + 双令牌 + 不存敏感明文。
对比JWT和传统的基于Session的认证方式的优缺点
下面用最清晰、最直白、面试常考的方式,对比 JWT 认证 和 传统 Session-Cookie 认证 的优缺点。
一、核心原理一句话总结
- Session-Cookie
客户端只存一个SessionID,服务端在内存 / Redis 里存用户完整会话信息。
→ 有状态认证 - JWT
令牌本身包含用户信息,服务端不存会话,只通过签名验证合法性。
→ 无状态认证
二、详细优缺点对比
1. 服务端状态
Session
- 优点:服务端完全控制会话,可随时销毁、踢人、修改权限
- 缺点:有状态,分布式环境必须共享 Session(Redis)
JWT
- 优点:无状态,服务端不存任何信息,水平扩展极其方便
- 缺点:令牌签发后无法主动作废,想踢人必须加黑名单
2. 分布式 / 微服务支持
Session
- 优点:简单、成熟
- 缺点:多服务器必须共享 Session,架构复杂
JWT
- 优点:天生支持分布式、微服务、跨域
- 缺点:无
3. 跨域与前后端分离
Session
- 优点:传统 Web 项目非常稳定
- 缺点:Cookie 跨域限制大,不适合前后端分离、小程序、APP
JWT
- 优点:完美支持跨域、APP、小程序、第三方 API
- 缺点:前端需要手动存储并携带令牌
4. 性能与请求大小
Session
- 优点:Cookie 很小,请求开销低
- 缺点:每次请求都要查 Redis / 数据库
JWT
- 优点:不用查库,验证极快
- 缺点:令牌较长,Header 占用带宽稍大
5. 安全性
Session
- 优点:信息存在服务端,不容易泄露
- 缺点:依赖 Cookie,易受 CSRF 攻击
JWT
- 优点:不依赖 Cookie,天然防 CSRF
- 缺点:Payload 只是编码不是加密,不能放敏感信息
- 一旦泄露,别人就能直接用(除非短过期 + HTTPS)
6. 令牌失效与管理
Session
- 优点:想踢人就删 Session,实时生效
- 缺点:无
JWT
- 优点:无
- 缺点:无法主动失效,必须靠过期或黑名单
7. 适用场景
Session
- 传统 Web 网站
- 单域名系统
- 需要频繁踢人、强制下线的后台系统
JWT
- 前后端分离(Vue/React)
- APP、小程序
- 微服务、API 开放平台
- SSO 单点登录
三、优缺点总结表(最精简版)
表格
| 对比项 | Session-Cookie | JWT |
|---|---|---|
| 状态 | 有状态,服务端存储 | 无状态,不存储 |
| 分布式支持 | 差,需共享 Session | 极好,天然支持 |
| 跨域 | 受 Cookie 限制 | 不受限,适合前后端分离 |
| 主动失效 | 容易,随时踢人 | 困难,需过期或黑名单 |
| 性能 | 需查库,略慢 | 验证快,无需查库 |
| 安全风险 | CSRF | 令牌泄露风险,不能存敏感明文 |
| 实现复杂度 | 简单,框架内置 | 稍复杂,需处理令牌存储、刷新 |
四、一句话结论
- 传统网站、后台管理系统 → 用 Session 更简单安全
- 前后端分离、APP、小程序、微服务、API 授权 → 用 JWT 更合适
JWT 与 Session 认证流程对比图
我用纯文本流程图给你画最清晰、最直观的版本,一眼看懂核心差异!
一、传统 Session-Cookie 认证流程
[客户端] 提交用户名+密码 [服务端]
│ ───────────────────────────────► │
│ │
│ │ 验证账号密码
│ │ 生成 Session 存储用户信息
│ │ 生成 SessionID
│ ◄─────────────────────────────── │
│ 返回 SessionID │
│
│ 浏览器自动保存到 Cookie
│
│ 后续请求(自动携带 Cookie)
│ ───────────────────────────────► │
│ │
│ │ 根据 SessionID 查询 Session
│ │ 验证通过 → 处理请求
│ │
│ ◄─────────────────────────────── │
│ 响应数据 │
核心特点
- 服务端存数据,客户端只存一个 ID
- 有状态,必须查会话库
- 浏览器自动带 Cookie
二、JWT 认证流程
[客户端] 提交用户名+密码 [服务端]
│ ───────────────────────────────► │
│ │
│ │ 验证账号密码
│ │ 生成 JWT(Header.Payload.Signature)
│ ◄─────────────────────────────── │
│ 返回 JWT │
│
│ 手动保存到 localStorage/Cookie
│
│ 后续请求(手动放在 Header)
│ Authorization: Bearer <JWT>
│ ───────────────────────────────► │
│ │
│ │ 验证 JWT 签名 + 过期时间
│ │ 无需查库 → 直接解析用户信息
│ │
│ ◄─────────────────────────────── │
│ 响应数据 │
核心特点
- 服务端不存任何数据
- 无状态,解析即认证
- 客户端手动带令牌
三、一眼看懂最大区别
Session:服务端存信息 → 客户端拿ID查信息
JWT:服务端不存信息 → 客户端拿令牌直接用
需要我把这两张流程图做成面试可直接背诵的极简版吗?