3. Python JWT 库介绍:PyJWT 安装、HS256 算法签名与验签示例

在 Python 生态中,PyJWT 是最广泛使用的 JWT 库之一。它轻量、安全,支持多种签名算法(HS256、RS256、ES256 等),并且与 Flask、Django、FastAPI 等框架无缝集成。本章将带你完成 PyJWT 的安装,并通过 HS256 对称算法实现完整的签名与验签流程。

3.1 PyJWT 安装与环境准备

PyJWT 可通过 pip 直接安装。建议在虚拟环境中进行,避免与系统级包冲突。

# 创建并激活虚拟环境(可选但推荐)
python -m venv venv
source venv/bin/activate  # Linux/macOS
# venv\Scripts\activate   # Windows

# 安装 PyJWT
pip install pyjwt

# 验证安装
python -c "import jwt; print(jwt.__version__)"
版本提示: 本文基于 PyJWT 2.8+。如果你使用旧版本(如 1.x),部分 API 名称和默认行为可能不同。建议升级到最新版。

3.2 HS256 算法核心概念

HS256(HMAC with SHA-256)是一种对称签名算法:签发和验证使用同一个密钥(secret)。其核心流程如下:

  • 签名(Sign):使用密钥对 Header + Payload 进行 HMAC-SHA256 运算,生成签名,附加到 JWT 末尾。
  • 验签(Verify):使用相同密钥对接收到的 JWT 重新计算签名,比对是否一致。若不一致,则拒绝该 Token。
安全警告: 对称密钥必须严格保密,不可硬编码在代码仓库中。生产环境应通过环境变量、密钥管理服务(如 AWS KMS、HashiCorp Vault)或配置中心注入。
HS256 签名与验签流程 HS256 对称签名与验签流程 签发方 (Issuer) 共享密钥 (Secret) 验证方 (Verifier) 使用密钥签名 使用相同密钥验签 JWT = Base64(Header) + "." + Base64(Payload) + "." + Signature 生成 传输 关键点: • 对称算法:签名与验签使用同一个密钥,速度快,适合内部服务间通信。 • 密钥分发:必须通过安全通道(如 TLS、密钥交换协议)共享密钥。

3.3 使用 HS256 签名 JWT

签名过程需要三个要素:Payload(载荷)、密钥、算法标识。PyJWT 的 jwt.encode() 函数自动完成 Header 构建、Base64 编码和签名计算。

import jwt
import datetime

# 1. 定义密钥(生产环境请从安全配置读取)
SECRET_KEY = "my-secret-key-2024"

# 2. 构建 Payload(标准声明 + 自定义声明)
payload = {
    "sub": "user_12345",           # 主题(用户ID)
    "name": "张三",                # 自定义声明
    "role": "admin",               # 自定义声明
    "iat": datetime.datetime.utcnow(),                    # 签发时间
    "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)  # 过期时间
}

# 3. 签名:指定算法为 HS256
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")

print("生成的 JWT:")
print(token)
输出示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMzQ1IiwibmFtZSI6IuW8oOS4iSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoxNzAwMDAzNjAwfQ.abc123def456...

3.4 使用 HS256 验证 JWT

验签使用 jwt.decode() 函数。PyJWT 会自动提取 Header 中的算法信息,使用提供的密钥重新计算签名并比对。若签名无效、Token 过期或格式错误,会抛出相应异常。

# 4. 验证 JWT(使用相同密钥)
try:
    decoded_payload = jwt.decode(
        token,
        SECRET_KEY,
        algorithms=["HS256"]   # 明确指定允许的算法
    )
    print("验签成功!Payload:")
    print(decoded_payload)
except jwt.ExpiredSignatureError:
    print("错误:Token 已过期")
except jwt.InvalidTokenError as e:
    print(f"错误:无效 Token - {e}")
最佳实践: algorithms 参数应明确指定为 ["HS256"],而不是留空或使用 None。这可以防止算法混淆攻击(Algorithm Confusion Attack),即攻击者将算法改为 none 或非对称算法来绕过验证。

3.5 常见异常与处理策略

异常类 触发条件 处理建议
ExpiredSignatureError Token 的 exp 时间已过 提示用户重新登录,或使用 Refresh Token 刷新
InvalidSignatureError 签名不匹配(密钥错误或 Token 被篡改) 拒绝请求,记录安全日志
DecodeError JWT 格式错误(段数不对、Base64 解码失败) 返回 400 Bad Request,提示客户端检查 Token 格式
InvalidAlgorithmError Token 的算法不在 algorithms 白名单中 拒绝请求,防止算法混淆攻击

3.6 完整示例:签名与验签一体化

以下代码将签名和验签封装为两个函数,便于在项目中复用:

import jwt
import datetime
from typing import Dict, Optional

SECRET_KEY = "my-secret-key-2024"

def sign_jwt(payload: Dict) -> str:
    """使用 HS256 签名 JWT"""
    # 自动添加 iat 和 exp(可选)
    payload.setdefault("iat", datetime.datetime.utcnow())
    payload.setdefault("exp", datetime.datetime.utcnow() + datetime.timedelta(hours=1))
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")

def verify_jwt(token: str) -> Optional[Dict]:
    """验证 JWT,成功返回 Payload,失败返回 None"""
    try:
        return jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    except jwt.PyJWTError:
        return None

# 使用示例
if __name__ == "__main__":
    user_payload = {"sub": "user_001", "name": "李四", "role": "editor"}
    token = sign_jwt(user_payload)
    print(f"Token: {token}")

    result = verify_jwt(token)
    if result:
        print(f"验证通过,用户: {result['name']}, 角色: {result['role']}")
    else:
        print("验证失败")

3.7 HS256 与 RS256 对比

HS256 适合内部服务间通信,RS256(RSA 非对称算法)适合跨信任域的场景。下表列出关键差异:

对比维度 HS256(对称) RS256(非对称)
密钥数量 1 个共享密钥 私钥 + 公钥(2 个)
签名速度 快 慢(约慢 10-100 倍)
验签速度 快 快(公钥验签)
密钥分发 需安全通道共享密钥 公钥可公开,私钥仅签发方持有
适用场景 微服务内部、单点登录(SSO) 第三方 API、跨组织认证
HS256 与 RS256 架构对比 HS256 对称 vs RS256 非对称架构 HS256(对称) 签发方 验证方 共享密钥 密钥需安全分发,不可泄露 RS256(非对称) 签发方 验证方 公钥 私钥仅签发方持有,公钥可公开

3.8 本章小结

  • PyJWT 安装简单,pip install pyjwt 即可使用。
  • HS256 是对称算法,签名与验签使用同一密钥,适合内部服务。
  • jwt.encode() 生成 Token,jwt.decode() 验证 Token,需明确指定 algorithms=["HS256"]。
  • 务必处理 ExpiredSignatureError、InvalidSignatureError 等异常,避免应用崩溃。
  • 对称密钥必须安全存储,非对称算法(RS256)适用于跨信任域场景。