JWT 完全解析
JWT 完全解析 —— 从原理到实践,掰开了揉碎了讲清楚
前言
最近在学习 FastAPI 时遇到了登录认证的问题,接触到了 JWT 这个概念。说实话刚看到 JWT 时一头雾水:它是什么?为什么登录要用它?跟 session 有什么区别?里面的那一长串乱码到底藏了什么秘密?
这篇文章就是我对 JWT 的完整学习笔记,力求掰开了、揉碎了,把每一个知识点都讲清楚。
目录
- JWT 是什么?
- 为什么需要 JWT?—— 从 Session 的痛点说起
- JWT 长什么样?
- JWT 的三部分:Header · Payload · Signature
- JWT 的工作流程(核心逻辑)
- JWT 的签名是怎么保证安全的?
- JWT 的优缺点
- JWT 在 FastAPI 中的实战
- 常见安全问题与防范
- 总结与脑图
1. JWT 是什么?
JWT 全称 JSON Web Token,读作 “jot”(/dʒɒt/)。
官方的定义是:一种紧凑的、URL 安全的、用于在双方之间传递声明(claims)的令牌格式。
翻译成人话就是:
JWT 是一段有结构的字符串,里面可以安全地存放一些信息(比如用户 ID、过期时间),而且这段字符串本身就可以证明”信息没有被篡改过”。
它有三个核心特点:
- 自包含(Self-contained):所有需要的信息都在 token 本身里,不需要查数据库来验证
- 紧凑(Compact):体积小,可以放在 URL 参数、HTTP Header、Cookie 中
- URL 安全:经过 Base64URL 编码,不含特殊字符
2. 为什么需要 JWT?—— 从 Session 的痛点说起
要理解 JWT 的价值,先得知道它解决了什么问题。
传统 Session 认证的工作方式
1 | 用户登录 → 服务器创建 Session → 把 Session ID 存到 Cookie 返回给浏览器 |
Session 的痛点
| 问题 | 说明 |
|---|---|
| 有状态 | 服务器必须保存 Session 信息,通常存数据库或内存 |
| 扩展性差 | 多台服务器部署时,Session 需要共享(redis 或粘性会话),增加架构复杂度 |
| 跨域困难 | Cookie 受同源策略限制,API 给移动端用就很麻烦 |
| CSRF 风险 | Cookie 自动携带的特性容易遭受跨站请求伪造攻击 |
JWT 如何解决这些问题
1 | 用户登录 → 服务器签发一个 JWT → 返回给前端 |
关键区别:服务器不需要存储 JWT。所有信息都在 token 里,验证签名即可确认 token 的真实性。
这就带来了几个好处:
- 无状态:服务器不存 session,水平扩展变得极其简单
- 跨域友好:前端手动传 token,不受同源策略限制
- 适合分布式:任何一台服务器只要知道密钥,就能验证 token
3. JWT 长什么样?
一个真实的 JWT 长这样:
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c |
是不是看着像乱码?别怕,拆开来看就清楚了。
它由三部分组成,用 . 分隔:
1 | [Header].[Payload].[Signature] |
也就是上面那个字符串对应:
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← Header |
每一部分都是 Base64URL 编码的,解码后就能看到真实内容。
4. JWT 的三部分:Header · Payload · Signature
4.1 Header(头部)
Header 通常由两部分信息组成:
1 | { |
alg告诉验证方:”我是用 HS256 算法签名的”typ告诉解析方:”这是一个 JWT”
这个 JSON 经过 Base64URL 编码,就是 JWT 的第一段。
4.2 Payload(载荷)
Payload 是存放实际信息的地方。这些信息被称为 claims(声明)。
Claims 分为三种:
注册声明(Registered Claims)
预定义的、建议使用的标准字段:
| 字段 | 全称 | 含义 |
|---|---|---|
iss |
Issuer | 签发者 |
sub |
Subject | 面向的用户 |
aud |
Audience | 接收方 |
exp |
Expiration Time | 过期时间(时间戳) |
nbf |
Not Before | 生效起始时间 |
iat |
Issued At | 签发时间 |
jti |
JWT ID | 唯一标识 |
公共声明(Public Claims)
可以自定义的字段,为避免冲突建议在 IANA JSON Web Token Registry 注册或使用命名空间。
私有声明(Private Claims)
双方约定的自定义字段,比如:
1 | { |
⚠️ 特别注意:Payload 只是 Base64URL 编码,不是加密!任何人都可以解码看到里面的内容。所以千万不要在 Payload 中存放密码、密钥等敏感信息。
4.3 Signature(签名)
签名是 JWT 安全性的核心。它的生成过程:
1 | HMACSHA256( |
简单说就是:
- 把编码后的 Header 和 Payload 用
.拼起来 - 用指定的算法(比如 HMAC-SHA256)对这个字符串做一次带密钥的哈希运算
- 得到的结果就是签名
签名的意义:由于签名需要密钥才能生成,如果 token 被篡改(比如把 role 从 user 改成 admin),重新计算签名会不匹配,验证就会失败。
5. JWT 的工作流程(核心逻辑)
理解了各部分之后,来看看 JWT 的完整生命周期。
5.1 签发阶段
1 | ┌─────────────┐ |
5.2 验证阶段
1 | ┌─────────────┐ |
5.3 核心逻辑总结
一句话概括:
服务器签发一个带签名的”通行证”给你,你每次来都带着它,服务器只需检查签名就知道这通行证是不是它发的、有没有被改过。
关键是服务器不存任何状态——这就是所谓的 Stateless(无状态)。
6. JWT 的签名是怎么保证安全的?
这是初学者最容易困惑的地方。我用一个类比来解释。
印章类比
想象你是一家公司的老板(服务器),你有一枚私人印章(密钥)。
1 | 你写了一张字条:"张三,级别:管理员" |
如果有人把字条改成”李四,级别:超级管理员”:
1 | 他没有你的私人印章 → 没有密钥 |
关键技术点
- 对称算法(HS256/HMAC):签发和验证用同一个密钥。简单但需要保护好密钥。
- 非对称算法(RS256/ES256):签发用私钥,验证用公钥。安全性更高,适合多方验证的场景。
| 特性 | HS256(对称) | RS256(非对称) |
|---|---|---|
| 密钥数量 | 1 个(对称密钥) | 2 个(私钥 + 公钥) |
| 计算速度 | 快 | 慢 |
| 密钥分发 | 必须保密 | 公钥可以公开 |
| 适用场景 | 单一服务内部 | 微服务/第三方认证 |
7. JWT 的优缺点
优点 ✅
| 优点 | 说明 |
|---|---|
| 无状态、易扩展 | 服务器不需要存储 token,水平扩展只需保证密钥一致 |
| 跨域友好 | 不依赖 Cookie,前端可以自由在多个域名间传递 |
| 自包含 | Payload 里存了用户信息,减少数据库查询 |
| 移动端友好 | App 不需要 Cookie 支持,存 token 即可 |
| 性能好 | 验证只需一次签名计算,不需要查库 |
| 标准化 | RFC 7519 标准,生态成熟,几乎所有语言都有实现 |
缺点 ❌
| 缺点 | 说明 |
|---|---|
| 不可撤销 | 签发后无法主动让 token 失效(除非维护黑名单——但这又回到有状态了) |
| Payload 不加密 | 敏感信息不能放进去,放了等于明文传输 |
| 体积较大 | 比 Session ID 长很多,每次请求都带着会增加带宽开销 |
| 过期时间难抉择 | 太短 → 用户频繁重新登录;太长 → 泄露风险高 |
| 密钥保护责任重大 | 密钥泄露 = 任何人都可以签发有效的 JWT |
| 无状态也是无审计 | 你无法知道某个 token 是什么时候撤销的、被谁使用了 |
对比 Session
| 维度 | Session | JWT |
|---|---|---|
| 存储位置 | 服务器 | 客户端 |
| 扩展性 | 差(需共享 Session) | 好(无状态) |
| 即时失效 | 可以(删 Session) | 难(维护黑名单) |
| 跨域 | 麻烦 | 简单 |
| 安全性 | CSRF 风险 | XSS 风险(token 被偷则全丢) |
8. JWT 在 FastAPI 中的实战
理论说完了,来看一个 FastAPI 中使用 JWT 的真实例子。
8.1 安装依赖
1 | pip install python-jose[cryptography] # JWT 生成与验证 |
python-jose 是 FastAPI 官方文档推荐的 JWT 库。passlib 用于安全地存储密码(永远不要存明文密码!)。
8.2 完整代码
1 | from datetime import datetime, timedelta, timezone |
8.3 关键代码解析
签发 JWT (create_access_token)
1 | def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: |
这里 jwt.encode() 帮我们做了所有底层工作:
- 把
to_encode(Payload)转成 JSON - 构造 Header
{"alg": "HS256", "typ": "JWT"} - 对 Header 和 Payload 做 Base64URL 编码
- 用密钥和指定算法计算签名
- 拼接成
Header.Payload.Signature格式
验证 JWT (verify_token)
1 | def verify_token(token: str) -> dict: |
jwt.decode() 帮我们做:
- 拆解 token 的三部分
- 用 SECRET_KEY 重新计算签名,对比是否一致
- 检查
exp字段是否过期 - 可选:检查
nbf、iss、aud等字段 - 如果一切 OK,返回 Payload
8.4 如何使用
1 | # 1. 登录获取 JWT |
9. 常见安全问题与防范
9.1 密钥泄露
问题:密钥被泄露 = 任何人都可以签发有效的 JWT。
防范:
- 密钥要用足够长、足够随机的字符串(至少 256 位)
- 存入环境变量,不要硬编码在代码里
- 定期轮换密钥
- 使用密钥管理服务(如 AWS KMS、HashiCorp Vault)
9.2 Token 被盗
问题:XSS 攻击窃取存在 localStorage 的 token。
防范:
- 使用 HttpOnly Cookie 存储 token(不能通过 JS 读取)
- 做好 XSS 防护(输入过滤、CSP 策略)
- 使用短期 token + refresh token 机制
- HTTPS 传输,防止中间人攻击
9.3 无法主动失效
问题:签发后的 JWT 在过期前无法主动撤销。
解决方案(几种常见做法):
| 方案 | 优点 | 缺点 |
|---|---|---|
| 短期 token + 刷新 token | token 几分钟过期,危害有限 | 架构复杂一些 |
| 维护黑名单 | 可以在 Redis 存已撤销的 jti | 回到有状态 |
| 版本号 | 用户密码修改时递增版本号,使旧 token 失效 | 每次请求都要查版本号 |
| 直接缩短过期时间 | 简单 | 用户频繁登录体验差 |
9.4 alg:none 攻击
问题:部分 JWT 库在实现时可能允许 alg: "none" 的 token(无签名)。
防范:在 decode 时显式指定允许的算法,不要接受 none。
1 | # ❌ 不安全 —— 可能接受 alg: none 的 token |
9.5 算法混淆攻击
问题:攻击者把 alg 从 RS256 改成 HS256,然后用公钥(公钥是公开的)作为 HMAC 的密钥来签名。
防范:始终验证算法与预期一致,且服务端 decode 时绑定算法和密钥。
9.6 Too Much in Payload
问题:把密码、信用卡号等敏感信息放进 Payload。
防范:记住 Payload 只是编码不是加密。需要敏感信息?要么用 JWE(JSON Web Encryption)加密整个 JWT,要么只放非敏感信息。
10. 总结与脑图
一句话总结
JWT 就是一个带签名的 JSON 数据包,服务器用它来证明”你确实是你说的人”,而且不需要在服务器存任何东西。
核心记忆点
1 | JWT = Header + Payload + Signature |
使用流程
1 | 登录 ──→ 服务器签发 JWT ──→ 前端存储 |
适用场景
| 适合 | 不适合 |
|---|---|
| 分布式系统 / 微服务 | 需要即时撤销 token 的场景 |
| 单页应用(SPA) | 对 token 大小敏感的物联网/低带宽场景 |
| 移动 App | 超长会话(如”记住我”30天) |
| API 对外提供 | 高度敏感数据(银行、医疗)—— 需要额外加密 |
| 跨域 / 跨平台认证 | — |
继续学习的方向
- OAuth 2.0 —— JWT 常作为 access token 用在 OAuth 2.0 中
- Refresh Token 机制 —— 解决 JWT 过期问题的最佳实践
- JWE(JSON Web Encryption) —— 对 JWT 整体加密
- JWK(JSON Web Key) —— 使用公钥体系签名和验证
- 双 token 模式 —— access token(短期)+ refresh token(长期)的组合方案
写在最后:JWT 不是银弹,它有自己的优势和局限。理解它的工作原理和适用场景,才能在项目中做出正确的技术选择。希望这篇文章能帮你彻底搞懂 JWT,在写 FastAPI 应用时能游刃有余!








