jwt工具类,支持HS256、RS256、SM3(SM3+HMAC)、SM2(SM3+SM2)、SM4(SM3+SM4)五种签名算法
Project description
JWT的签发与验证组件
1. 组件整体说明
py-jwt-helper 是一个轻量级的 JWT 工具库,封装了密钥生成、JWT 签发、验签、载荷提取以及 JWKS 构建与解析等完整流程。
核心特性:
- 统一 Base64 密钥格式 — 对称密钥与非对称公私钥对外均以 Base64 字符串传递,内部按算法自动解析
- 五种签名算法 — HS256、RS256、SM3(SM3+HMAC)、SM2(SM3+SM2)、SM4(SM3+SM4)
- JWK/JWKS 标准兼容 — 支持 RFC 7517 格式的 JWKS 构建、解析与 kid 自动匹配
- 非侵入式国密扩展 — 通过 PyJWT 的
register_algorithm()注入国密算法,不修改 PyJWT 源码 - FastAPI 集成 — 提供多系统签发隔离的鉴权依赖注入
2. 组件依赖加载
安装
# 基础安装
pip install py-jwt-helper
# 如需 FastAPI 集成
pip install py-jwt-helper[fastapi]
运行时依赖
| 依赖 | 版本要求 | 用途 |
|---|---|---|
| PyJWT[crypto] | >= 2.8.0 | JWT 编解码与算法框架 |
| cryptography | >= 46.0.5 | RSA 密钥生成与 PEM 解析 |
| gmssl | >= 3.2.2 | 国密 SM2/SM3/SM4 算法实现 |
国密算法注册
使用 SM2、SM3、SM4 算法前,需先注册国密扩展:
from py_jwt_helper.jwt.extensions import register_sm_crypto_algorithms
register_sm_crypto_algorithms()
建议在应用启动时调用一次即可。
导入
from py_jwt_helper import JwtHelper, JwtPayload, JwkHelper, JwkKeyEntry
3. 核心接口功能说明
3.1. 算法支持与加签逻辑
3.1.1. 支持的算法说明
| 算法 | 类型 | 密钥长度 | 签名方式 | JWK kty |
|---|---|---|---|---|
| HS256 | 对称 | 32 字节 | HMAC-SHA256(key, msg) | oct |
| SM3 | 对称 | 32 字节 | HMAC-SM3(key, msg),与 HS256 结构相同 | oct |
| SM4 | 对称 | 16 字节 | SM4-CBC 加密取最后分组作 MAC | oct |
| RS256 | 非对称 | 2048 位 | RSASSA-PKCS1-v1_5,SHA-256哈希 + RSA私钥签名 | RSA |
| SM2 | 非对称 | 私钥 32 字节 / 公钥 64 字节 | SM3哈希 + SM2椭圆曲线签名 | EC (crv=SM2) |
- 对称算法:加签与验签使用同一密钥
- 非对称算法:私钥加签,公钥验签;SM2 由于内部
prepare_key兼容,私钥也可用于验签
3.1.2. 生成各算法的密钥的接口和结果说明
JwtHelper.generate_key_or_keypair(alg)
根据算法名生成密钥,统一返回 Base64 编码格式。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
alg |
str |
算法名称,支持 HS256、SM3、SM4、RS256、SM2 |
返回值:
- 对称算法(HS256 / SM3 / SM4):返回
str— Base64 编码的密钥字符串 - 非对称算法(RS256 / SM2):返回
Dict[str, str],结构为:
{
"private_key": "Base64编码的私钥",
"public_key": "Base64编码的公钥"
}
调用示例:
from py_jwt_helper import JwtHelper
from py_jwt_helper.jwt.extensions import register_sm_crypto_algorithms
register_sm_crypto_algorithms()
## 对称算法 — 返回单个 Base64 字符串
hs256_key = JwtHelper.generate_key_or_keypair("HS256")
## 例: "KU49TG81ii+VKtP2WV4/jaZGh4AOvyW5WUXcxnvsqMs="
sm3_key = JwtHelper.generate_key_or_keypair("SM3")
sm4_key = JwtHelper.generate_key_or_keypair("SM4")
# 非对称算法 — 返回 dict
rsa_keys = JwtHelper.generate_key_or_keypair("RS256")
# 例: {"private_key": "LS0tLS1CRUdJTi...", "public_key": "LS0tLS1CRUdJTi..."}
sm2_keys = JwtHelper.generate_key_or_keypair("SM2")
# 例: {"private_key": "IesuWFlC5RgjS7IX...", "public_key": "BHzn7neIZZX6t3VA..."}
JwtHelper.get_public_key_from_private(secret_key, alg)
基于非对称算法的私钥推导其对应的公钥。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
secret_key |
str |
Base64 编码的私钥字符串 |
alg |
str |
算法类型,仅支持 RS256、SM2 |
返回值: str — Base64 编码的公钥字符串
调用示例:
sm2_keys = JwtHelper.generate_key_or_keypair("SM2")
pub_key = JwtHelper.get_public_key_from_private(sm2_keys["private_key"], "SM2")
assert pub_key == sm2_keys["public_key"]
3.1.3. 基于各算法生成 JWT 的接口说明
JwtHelper.create_jwt(secret_key, sub, expire_second, ...)
创建一个完整的 JWT 字符串。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
secret_key |
str |
是 | Base64 编码的密钥。对称算法为共享密钥;非对称算法为私钥 |
sub |
str |
是 | JWT 主题内容或标识,通常存放业务数据 |
expire_second |
int |
是 | 有效期(秒)。负值可生成已过期的 token 用于测试 |
iss |
str |
否 | 签发者身份标识 |
before_second |
int |
否 | 延迟生效时间(秒),生成 nbf 声明。必须小于 expire_second |
alg |
str |
否 | 签名算法,默认 "RS256" |
kid |
str |
否 | 密钥 ID,写入 JWT Header,用于 JWKS 场景中按 kid 匹配验签密钥 |
返回值: str — 编码后的 JWT 字符串
调用示例:
from py_jwt_helper import JwtHelper
# 对称算法签名
key = JwtHelper.generate_key_or_keypair("HS256")
token = JwtHelper.create_jwt(
secret_key=key,
sub="user_001",
expire_second=3600,
iss="my_service",
alg="HS256",
kid="hs256-key-1"
)
# 非对称算法签名(私钥签发)
rsa_keys = JwtHelper.generate_key_or_keypair("RS256")
token = JwtHelper.create_jwt(
secret_key=rsa_keys["private_key"],
sub="user_002",
expire_second=1800,
iss="auth_server",
alg="RS256",
kid="rsa-key-1"
)
# sub 中存放 JSON 业务数据
import json
payload_data = {"providerId": "hr", "id": "00001", "name": "张三"}
token = JwtHelper.create_jwt(
secret_key=rsa_keys["private_key"],
sub=json.dumps(payload_data, ensure_ascii=False),
expire_second=86400 * 30,
alg="RS256"
)
3.2. 验签相关逻辑
3.2.1. 多密钥/公钥 + kid 生成 JWKS 信息说明
JwkKeyEntry — JWKS 构建入参实体
| 字段 | 类型 | 说明 |
|---|---|---|
alg |
str |
算法名称(HS256 / SM3 / SM4 / RS256 / SM2) |
kid |
str |
密钥 ID,用于在 JWKS 中唯一标识该密钥 |
key |
str |
Base64 编码的验签密钥。对称算法为共享密钥,非对称算法为公钥 |
JwkHelper.build_jwks(keys)
根据传入的验签密钥列表构建标准的 JWKS(JSON Web Key Set)结构。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
keys |
List[JwkKeyEntry] |
JwkKeyEntry 列表 |
返回值: Dict — 标准 JWKS 结构
{
"keys": [
{
"alg": "HS256",
"kid": "hs256-1",
"use": "sig",
"kty": "oct",
"k": "<Base64Url 编码的对称密钥>"
},
{
"alg": "RS256",
"kid": "rsa-1",
"use": "sig",
"kty": "RSA",
"n": "<Base64Url 编码的模数>",
"e": "<Base64Url 编码的指数>"
},
{
"alg": "SM2",
"kid": "sm2-1",
"use": "sig",
"kty": "EC",
"crv": "SM2",
"x": "<Base64Url 编码的 X 坐标>",
"y": "<Base64Url 编码的 Y 坐标>"
}
]
}
调用示例:
from py_jwt_helper import JwtHelper, JwkHelper, JwkKeyEntry
# 生成各算法密钥
hs256_key = JwtHelper.generate_key_or_keypair("HS256")
sm3_key = JwtHelper.generate_key_or_keypair("SM3")
rsa_keys = JwtHelper.generate_key_or_keypair("RS256")
sm2_keys = JwtHelper.generate_key_or_keypair("SM2")
# 构建入参列表(非对称算法使用公钥)
entries = [
JwkKeyEntry(alg="HS256", kid="hs256-1", key=hs256_key),
JwkKeyEntry(alg="SM3", kid="sm3-1", key=sm3_key),
JwkKeyEntry(alg="RS256", kid="rsa-1", key=rsa_keys["public_key"]),
JwkKeyEntry(alg="SM2", kid="sm2-1", key=sm2_keys["public_key"]),
]
jwks = JwkHelper.build_jwks(entries)
# jwks 可直接作为 JSON 响应暴露到 /.well-known/jwks.json 端点
3.2.2. 基于带有 kid 的 JWT 或 JWKS 中匹配验签密钥/公钥的说明
JwkHelper.get_key_from_jwk(jwk)
从单个 JWK 字典中提取验签密钥。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
jwk |
Dict |
单个 JWK 字典(非 JWKS,需从 jwks["keys"][i] 获取) |
返回值: str — Base64 编码的验签密钥字符串
JwkHelper.resolve_key_from_jwks(jwks, token)
根据 JWT Header 中的 kid 从 JWKS 中自动匹配对应的 JWK,并提取验签密钥。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
jwks |
Dict |
标准 JWKS 字典 {"keys": [...]} |
token |
str |
JWT 字符串(Header 中需包含 kid) |
返回值: str — Base64 编码的验签密钥字符串
调用示例:
from py_jwt_helper import JwtHelper, JwkHelper, JwkKeyEntry
# 1. 构建多密钥 JWKS
rsa_keys = JwtHelper.generate_key_or_keypair("RS256")
sm2_keys = JwtHelper.generate_key_or_keypair("SM2")
entries = [
JwkKeyEntry(alg="RS256", kid="rsa-1", key=rsa_keys["public_key"]),
JwkKeyEntry(alg="SM2", kid="sm2-1", key=sm2_keys["public_key"]),
]
jwks = JwkHelper.build_jwks(entries)
# 2. 用私钥签发带 kid 的 JWT
token = JwtHelper.create_jwt(
secret_key=rsa_keys["private_key"],
sub="user_001",
expire_second=3600,
alg="RS256",
kid="rsa-1"
)
# 3. 根据 token 中的 kid 自动匹配并提取验签密钥
resolved_key = JwkHelper.resolve_key_from_jwks(jwks, token)
# resolved_key 将匹配 kid="rsa-1" 对应的公钥
# 4. 验签
payload = JwtHelper.verify_jwt(token, resolved_key)
3.2.3. JWT 验签和 Payload 信息获取的结构说明
JwtHelper.verify_jwt(token, secret_key)
校验 JWT 的签名有效性、过期时间、生效时间等。校验失败会抛出 jwt.exceptions.PyJWTError 的相关子类。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
token |
str |
JWT 字符串 |
secret_key |
str |
Base64 编码的验签密钥。对称算法为共享密钥;非对称算法为公钥 |
返回值: JwtPayload — 载荷实体对象
可能抛出的异常:
| 异常类 | 说明 |
|---|---|
jwt.exceptions.DecodeError |
token 格式错误或 Header 缺少算法 |
jwt.exceptions.ExpiredSignatureError |
token 已过期 |
jwt.exceptions.ImmatureSignatureError |
token 尚未生效(nbf) |
jwt.exceptions.InvalidSignatureError |
签名不匹配 |
JwtHelper.extract_payload(token)
忽略签名,仅提取 JWT 的 Payload 部分(适用于不需要验签的调试场景)。
参数:
| 参数 | 类型 | 说明 |
|---|---|---|
token |
str |
JWT 字符串 |
返回值: JwtPayload — 载荷实体对象
JwtPayload — 载荷实体
继承自 dict,可直接作为字典使用,同时提供以下便捷属性:
| 属性 | 类型 | 说明 |
|---|---|---|
exp_time |
datetime | None |
过期时间(UTC),对应 exp 声明 |
iat_time |
datetime | None |
签发时间(UTC),对应 iat 声明 |
nbf_time |
datetime | None |
生效时间(UTC),对应 nbf 声明 |
iss |
str | None |
签发者,对应 iss 声明 |
sub |
str | None |
主题内容,对应 sub 声明 |
所有标准 JWT 声明及自定义字段均可通过字典访问,如 payload["sub"]、payload.get("custom_field")。
调用示例:
from py_jwt_helper import JwtHelper
# 验签并获取 payload
try:
payload = JwtHelper.verify_jwt(token, public_key)
print(payload.sub) ## "user_001"
print(payload.iss) ## "auth_server"
print(payload.exp_time) ## datetime(2026, 5, 26, 12, 0, 0, tzinfo=UTC)
print(payload.iat_time) ## datetime(2026, 5, 25, 12, 0, 0, tzinfo=UTC)
print(payload["sub"]) ## 字典方式访问,等价于 payload.sub
except jwt.exceptions.ExpiredSignatureError:
print("Token 已过期")
except jwt.exceptions.InvalidSignatureError:
print("签名无效")
# 仅提取 payload(不验签)
payload = JwtHelper.extract_payload(token)
print(payload.sub)
完整端到端示例:
from py_jwt_helper import JwtHelper, JwkHelper, JwkKeyEntry
from py_jwt_helper.jwt.extensions import register_sm_crypto_algorithms
register_sm_crypto_algorithms()
# 1. 生成密钥
rsa_keys = JwtHelper.generate_key_or_keypair("RS256")
# 2. 构建入参并生成 JWKS
entries = [JwkKeyEntry(alg="RS256", kid="rsa-1", key=rsa_keys["public_key"])]
jwks = JwkHelper.build_jwks(entries)
# 3. 签发 JWT
token = JwtHelper.create_jwt(
secret_key=rsa_keys["private_key"],
sub="user_001",
expire_second=3600,
iss="auth_server",
alg="RS256",
kid="rsa-1"
)
# 4. 从 JWKS 中自动匹配密钥并验签
resolved_key = JwkHelper.resolve_key_from_jwks(jwks, token)
payload = JwtHelper.verify_jwt(token, resolved_key)
print(f"用户: {payload.sub}, 签发者: {payload.iss}, 过期: {payload.exp_time}")
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file py_jwt_helper-0.1.2.tar.gz.
File metadata
- Download URL: py_jwt_helper-0.1.2.tar.gz
- Upload date:
- Size: 12.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5fc3594deaf6ec0a7f9f0fedc1c5950cd7cf26459a56d537533b348767d59bf0
|
|
| MD5 |
33d16aaaa343daf54c99041e867535a2
|
|
| BLAKE2b-256 |
bb0cb946dfd95933366402174d86ce1873af2365f72aeee8a7118a15e1ec2a27
|
File details
Details for the file py_jwt_helper-0.1.2-py3-none-any.whl.
File metadata
- Download URL: py_jwt_helper-0.1.2-py3-none-any.whl
- Upload date:
- Size: 16.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddc9fb8a68b1e5c304740f2a03843a57aa8203ce8d89bf2a71f198acbcccb364
|
|
| MD5 |
5f8b6ccfa31259dee0d069979246cf54
|
|
| BLAKE2b-256 |
a073632b2df925f25b294134f328e6bcde9fae23c62b36eefa78e7a712fee97e
|