在 Python 中处理 JWT(JSON Web Token) 时,PyJWTpython-jose[cryptography] 是两个主流库,它们功能相似但定位和生态不同。下面我将从 功能、安全性、使用场景、FastAPI 兼容性 等角度为你详细对比,并给出明确建议。


🔑 一、核心结论(先看这个)

项目推荐使用
新项目(尤其是 FastAPI)python-jose[cryptography]
简单 JWT 签发/验证(无 JWE/JWK)⚠️ PyJWT 也可用
需要 JWE(加密 JWT)、JWK(密钥集)等完整 JOSE 支持✅ 必须用 python-jose
FastAPI 官方文档示例✅ 使用 python-jose
💡 一句话总结
如果你用 FastAPI 做认证(如 OAuth2、JWT 登录),直接选 python-jose[cryptography],它是社区事实标准。

📦 二、库简介

1. PyJWT

  • GitHub: https://github.com/jpadilla/pyjwt
  • 安装:pip install PyJWT
  • 特点:

    • 轻量级,仅支持 JWS(签名 JWT)
    • 不支持 JWE(加密 JWT)
    • 默认不包含加密后端(需额外安装 cryptography
  • 示例:

    import jwt
    token = jwt.encode({"sub": "123"}, "secret", algorithm="HS256")

2. python-jose

  • GitHub: https://github.com/mpdavis/python-jose
  • 安装:pip install "python-jose[cryptography]"

    • [cryptography] 表示包含加密后端(基于 cryptography 库)
  • 特点:

    • 实现完整的 JOSE 规范(JWS + JWE + JWK)
    • 支持 RSA、ECDSA、HMAC 等多种算法
    • FastAPI 官方教程 采用
  • 示例:

    from jose import jwt
    token = jwt.encode({"sub": "123"}, "secret", algorithm="HS256")
🔍 注意:两者 API 非常相似(因为都遵循 RFC 7519),但 不是完全兼容

🔍 三、详细对比

特性PyJWTpython-jose[cryptography]
JWS(签名)
JWE(加密)
JWK(密钥集)
算法支持HMAC, RSA, ECDSA更全面(包括 AES-GCM 等 JWE 算法)
FastAPI 官方推荐
依赖大小较小(+ cryptography)较大(自带完整 JOSE 实现)
错误信息友好度一般更清晰(如 JWTError, ExpiredSignatureError
Python 类型提示较弱较好
维护活跃度活跃活跃

🛡 四、安全性与依赖

两者都依赖 cryptography 库做底层加密

  • 所以安装时通常都要:

    pip install PyJWT[crypto]          # 或手动 pip install cryptography
    pip install "python-jose[cryptography]"
⚠️ 不要用纯 Python 实现的算法(如 PyJWT 不带 cryptography)—— 性能差且不安全!

🧪 五、代码示例对比

场景:签发和验证 HS256 JWT

✅ PyJWT

import jwt
from jwt.exceptions import ExpiredSignatureError, InvalidTokenError

SECRET_KEY = "my-secret"
ALGORITHM = "HS256"

# 签发
token = jwt.encode(
    {"sub": "user123", "exp": 1734567890},
    SECRET_KEY,
    algorithm=ALGORITHM
)

# 验证
try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
except ExpiredSignatureError:
    print("Token expired")
except InvalidTokenError:
    print("Invalid token")

✅ python-jose

from jose import jwt, ExpiredSignatureError, JWTError

SECRET_KEY = "my-secret"
ALGORITHM = "HS256"

# 签发
token = jwt.encode(
    {"sub": "user123", "exp": 1734567890},
    SECRET_KEY,
    algorithm=ALGORITHM
)

# 验证
try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
except ExpiredSignatureError:
    print("Token expired")
except JWTError:
    print("Invalid token")

🔁 几乎一样!但注意异常类名不同

  • PyJWT: InvalidTokenError
  • python-jose: JWTError

🚀 六、为什么 FastAPI 官方用 python-jose?

FastAPI 的 官方安全教程 明确使用:

from jose import jwt

原因:

  1. 历史选择:早期 PyJWT 对异步/类型提示支持较弱
  2. 错误分类更细ExpiredSignatureErrorJWTClaimsError 等便于处理
  3. 社区惯性:大量 FastAPI 项目沿用此方案,生态工具(如 fastapi-users)也基于它
📌 如果你用 FastAPI,保持一致性比“哪个更好”更重要

🧩 七、高级功能:只有 python-jose 支持

1. JWE(加密 JWT)

from jose import jwe

encrypted = jwe.encrypt("payload", key, encryption="A256GCM")
decrypted = jwe.decrypt(encrypted, key)

2. JWK(从公钥 URL 加载密钥)

from jose import jwk
keys = jwk.get_jwk_keys_from_url("https://example.com/.well-known/jwks.json")
这在对接 Auth0、Firebase、AWS Cognito 等第三方 IDP 时非常有用。

🛑 八、常见陷阱

1. 混淆两个库的 API

# 错误!混用会导致奇怪问题
import jwt  # 可能是 PyJWT
from jose import jwt as jose_jwt  # 又引入另一个 jwt

✅ 正确做法:只选一个,全项目统一

2. 忘记安装加密后端

# PyJWT 必须显式安装 crypto 支持
pip install PyJWT[crypto]

# python-jose 必须带 [cryptography]
pip install "python-jose[cryptography]"

否则会报错:Algorithm not supported


✅ 九、最终建议

你的场景推荐
FastAPI / Starlette 项目python-jose[cryptography]
简单脚本、内部工具⚠️ PyJWT[crypto] 也可以
需要 JWE / JWK / 企业级 OIDCpython-jose[cryptography]
追求最小依赖⚠️ PyJWT(但差别不大)
🔥 对于你的项目(FastAPI + Tortoise-ORM + 用户认证)
毫不犹豫选择 python-jose[cryptography] —— 它是 FastAPI 生态的标准。

📦 十、安装命令(复制即用)

# 推荐:python-jose(带加密支持)
pip install "python-jose[cryptography]"

# 备选:PyJWT(带加密支持)
pip install "PyJWT[crypto]"

然后在代码中:

# FastAPI 风格(推荐)
from jose import jwt, JWTError, ExpiredSignatureError