
今天这篇文章,目标很明确:
帮你把 JWT 从"听过"变成"会用",并给你一个能直接跑起来的 Python + FastAPI 鉴权项目。
一、JWT 是什么?先记一句话
JWT 全称是 JSON Web Token 。
它是一种"紧凑、URL 安全"的令牌格式,用来在客户端和服务端之间传递认证信息。
典型 JWT 长这样(3 段):
xxxxx.yyyyy.zzzzz
三段分别是:
- Header(头部)
- Payload(载荷)
- Signature(签名)
二、为什么会有 JWT?
传统 Session 方案中,服务端要保存会话状态;
而 JWT 走的是"无状态认证"思路:
- 登录成功后,服务端签发 token 给客户端
- 客户端后续每次请求带上 token
- 服务端只要验签 + 校验声明,就能确认身份
好处:
- 更适合前后端分离和分布式部署
- 不依赖服务端 Session 共享
- 跨服务传递身份信息更方便
三、JWT 出现前,token 一般怎么做?
很多同学会把"token"直接等同于 JWT。
其实在 JWT 普及前(包括现在),最常见的 token 方案有这几类:
Session ID(会话 ID)Opaque Token(不透明令牌)API Key(接口密钥)SAML票据/断言(企业场景较多)
先记一个核心区别:
JWT:token 里通常"自带信息"(可解码看到 claims)- 传统 token:token 本身通常是随机串,真正信息在服务端查
1)Session + Cookie(Web 时代主流)
怎么得到:
- 用户登录(用户名/密码)
- 服务端验证通过,创建 session 记录(用户 ID、过期时间等)
- 返回
session_id给浏览器(一般放 Cookie)
怎么用:
- 浏览器后续请求自动携带 Cookie
- 服务端拿
session_id去内存/Redis/DB 查会话 - 查到放行,查不到就要求重新登录
优点:简单、可立即失效
缺点:服务端要存状态,分布式要做 session 共享
2)Opaque Token(OAuth2 早期常见)
很多授权服务器签发的 access token,本质是随机串而非 JWT。
怎么得到:
- 走 OAuth2 流程(授权码、客户端凭证等)
- 授权服务器签发随机 token
怎么用:
- 客户端带
Authorization: Bearer <token> - 资源服务器去授权服务器做内省(introspection)或查本地缓存
- 校验通过再放行
特点:集中控制、易撤销;但每次校验可能多一次网络开销
3)API Key(更早、更简单)
怎么得到:
- 在平台后台创建应用,拿到
api_key(有时还配api_secret)
怎么用:
- 一般放请求头(不推荐放 URL 查询参数)
- 服务端校验 key 是否有效、权限范围、调用配额
适合服务到服务调用,但通常更偏"应用身份",不太适合用户登录态。
为什么后来 JWT 很火?
因为它特别适合前后端分离和微服务:
- 服务端可无状态验证(不一定每次查库)
- 跨服务传递用户身份方便
- 标准化字段明确(
claims、exp、iss、aud)
但代价是默认难"立即撤销",所以生产中常配套:
短时效 access token + refresh token + 黑名单机制。
四、JWT 三段式结构
1)Header
描述 token 元数据,比如签名算法:
json
{
"alg": "HS256",
"typ": "JWT"
}
2)Payload
存放声明(Claims),比如用户 ID、过期时间:
json
{
"sub": "alice",
"role": "admin",
"exp": 1760000000
}
重点:Payload 是 Base64URL 编码,不是加密。
不要放密码、银行卡号等敏感数据。
3)Signature
签名用于防篡改,核心公式:
sign(base64url(header) + "." + base64url(payload), secret/private_key)
服务端收到 token 后会重新验签,一旦不一致就拒绝。
五、RFC 7519 里最常用的标准声明
JWT 标准(RFC 7519)里常见声明:
iss:签发者(issuer)sub:主题(subject,一般放用户唯一标识)aud:受众(audience)exp:过期时间nbf:生效时间(not before)iat:签发时间(issued at)jti:JWT 唯一 ID
初学者至少要把 sub + exp 用好,进阶再加 iss/aud/jti。
六、JWT 的完整工作流(登录鉴权)
- 用户提交用户名密码到登录接口
- 服务端验证通过,签发 Access Token
- 客户端把 token 放在请求头:
Authorization: Bearer <token> - 服务端校验签名、过期时间、用户信息
- 校验通过,放行受保护接口;失败返回
401
七、JWT 安全使用的 8 条实践建议
- 全链路必须
HTTPS - Access Token 有效期要短(如 15~30 分钟)
- 明确校验
exp,不要只验签名 - 不要在 Payload 放敏感信息
- 强制算法白名单(避免算法混淆)
- 密钥不要硬编码到仓库,使用环境变量
- 需要"退出立即失效"时,引入黑名单/版本号机制
- 高风险接口增加二次校验(短信、密码二验等)
八、HS256 vs RS256:初学者如何选
HS256(对称)
- 签名和验签使用同一密钥
- 部署简单,性能好
- 适合单体或小规模服务
RS256(非对称)
- 私钥签名,公钥验签
- 服务间验证更安全,便于密钥管理
- 适合微服务或多系统协作
初学者实战可以先用 HS256,理解流程后再升级 RS256。
九、实战项目:FastAPI JWT 鉴权 API
本文配套项目目录:fastapi_jwt_demo
技术栈:
- Python 3.10+
- FastAPI
- Uvicorn
- python-jose
- passlib
项目实现:
- 用户登录:
POST /api/v1/auth/login - 获取当前用户:
GET /api/v1/users/me(需要 token) - 待办列表:
GET /api/v1/todos(需要 token) - 创建待办:
POST /api/v1/todos(需要 token)
核心演示点:
- 登录后签发 JWT(含
sub、exp) - Bearer Token 鉴权
- 过期 token 自动
401 - 密码哈希存储(不是明文)
十、初学者最常见 6 个坑
坑 1:把敏感信息放进 Payload
错。JWT 默认可解码,Payload 不是保险箱。
坑 2:把超长有效期 access token 当常规方案
风险很高。泄露后攻击窗口太长。
坑 3:只校验签名,不校验 exp/nbf
会让过期 token 继续可用。
坑 4:密钥写死在代码里并上传仓库
这是安全事故高发点。
坑 5:把 JWT 当"可撤销 session"
JWT 天生无状态,不加额外机制就很难立即撤销。
坑 6:没区分"认证"和"授权"
JWT 证明"你是谁",权限控制还需要业务层规则。
十一、给初学者的学习路径
- 先实现登录 +
/users/me - 再给业务接口加鉴权依赖
- 增加 token 过期处理
- 再做 refresh token
- 最后引入数据库与权限模型(RBAC)
这样走,一周内你就能把 JWT 鉴权跑通并解释清楚。
十二、参考资料
- RFC 7519 官方标准:
https://www.rfc-editor.org/rfc/rfc7519.html - IANA JWT Claims 注册表:
https://www.iana.org/assignments/jwt - FastAPI 官方 JWT 教程:
https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ - 阮一峰《JSON Web Token 入门教程》:
https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html