JWT 到底怎么用?一篇讲透 + FastAPI 鉴权实战

今天这篇文章,目标很明确:

帮你把 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 时代主流)

怎么得到:

  1. 用户登录(用户名/密码)
  2. 服务端验证通过,创建 session 记录(用户 ID、过期时间等)
  3. 返回 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 很火?

因为它特别适合前后端分离和微服务:

  • 服务端可无状态验证(不一定每次查库)
  • 跨服务传递用户身份方便
  • 标准化字段明确(claimsexpissaud

但代价是默认难"立即撤销",所以生产中常配套:

短时效 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 的完整工作流(登录鉴权)

  1. 用户提交用户名密码到登录接口
  2. 服务端验证通过,签发 Access Token
  3. 客户端把 token 放在请求头:
    Authorization: Bearer <token>
  4. 服务端校验签名、过期时间、用户信息
  5. 校验通过,放行受保护接口;失败返回 401

七、JWT 安全使用的 8 条实践建议

  1. 全链路必须 HTTPS
  2. Access Token 有效期要短(如 15~30 分钟)
  3. 明确校验 exp,不要只验签名
  4. 不要在 Payload 放敏感信息
  5. 强制算法白名单(避免算法混淆)
  6. 密钥不要硬编码到仓库,使用环境变量
  7. 需要"退出立即失效"时,引入黑名单/版本号机制
  8. 高风险接口增加二次校验(短信、密码二验等)

八、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(含 subexp
  • Bearer Token 鉴权
  • 过期 token 自动 401
  • 密码哈希存储(不是明文)

十、初学者最常见 6 个坑

坑 1:把敏感信息放进 Payload

错。JWT 默认可解码,Payload 不是保险箱。

坑 2:把超长有效期 access token 当常规方案

风险很高。泄露后攻击窗口太长。

坑 3:只校验签名,不校验 exp/nbf

会让过期 token 继续可用。

坑 4:密钥写死在代码里并上传仓库

这是安全事故高发点。

坑 5:把 JWT 当"可撤销 session"

JWT 天生无状态,不加额外机制就很难立即撤销。

坑 6:没区分"认证"和"授权"

JWT 证明"你是谁",权限控制还需要业务层规则。


十一、给初学者的学习路径

  1. 先实现登录 + /users/me
  2. 再给业务接口加鉴权依赖
  3. 增加 token 过期处理
  4. 再做 refresh token
  5. 最后引入数据库与权限模型(RBAC)

这样走,一周内你就能把 JWT 鉴权跑通并解释清楚。


十二、参考资料

相关推荐
zhangchaoxies2 小时前
JavaScript中Tree-shaking失效的场景及其优化对策
jvm·数据库·python
2501_914245932 小时前
SQL在GROUP BY中如何保留非聚合列_配合ANY_VALUE或窗口函数
jvm·数据库·python
A7bert7772 小时前
【YOLOv8部署至RDK X5】模型训练→转换bin→Sunrise 5部署
c++·人工智能·python·深度学习·yolo·机器学习
weixin_580614002 小时前
如何防止SQL注入篡改数据_实施双重身份验证与授权
jvm·数据库·python
2401_897190552 小时前
SQL视图占空间吗_理解视图定义与存储机制的底层逻辑
jvm·数据库·python
qq_424098562 小时前
C#怎么实现UDP广播通信_C#如何搭建Socket网络【核心】
jvm·数据库·python
2501_914245932 小时前
Python Web开发如何防范SQL注入_使用参数化查询与ORM实践
jvm·数据库·python
yejqvow122 小时前
Golang怎么做模糊测试fuzz_Golang Fuzz测试教程【高效】
jvm·数据库·python
2401_897190552 小时前
mysql如何通过mysqldump备份视图与触发器_使用相关参数
jvm·数据库·python