Metadata-Version: 2.4
Name: py-jwt-helper
Version: 0.1.1
Summary: jwt工具类，支持HS256、RS256、SM3(SM3+HMAC)、SM2(SM3+SM2)、SM4(SM3+SM4)五种签名算法
Author-email: ferdinand <gongjpa@gmail.com>
License: MIT
Keywords: jwt,jwt-helper,rsa,sm3,sm4
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.12
Requires-Dist: cryptography>=46.0.5
Requires-Dist: gmssl>=3.2.2
Requires-Dist: pyjwt[crypto]>=2.8.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.110.0; extra == 'fastapi'
Requires-Dist: httpx>=0.28.1; extra == 'fastapi'
Description-Content-Type: text/markdown

# py-jwt-helper

`py-jwt-helper` 是一个企业级的 JWT 扩展与辅助工具库。它在 `PyJWT` 基础上进行了深度国密算法（SM2, SM3, SM4）非侵入式扩展，并支持快捷的 FastAPI 依赖注入。

本库支持五种常用的对称与非对称算法：`HS256`, `RS256`, `SM3` (SM3-HMAC), `SM2` (带 Z 值预处理的签名), `SM4` (SM4-CBC-MAC)。同时为您封装了统一且简易的 Base64 格式密钥管理方案，以及基于 Payload 的强类型属性自动解析（自动将时间戳转化为 `datetime` 对象）。

| 算法  |  类型  |               签名逻辑                |
|------|--------|----------------------------------------|
| HS256  | 对称   | HMAC-SHA256(key, msg)                 |
| SM3    | 对称   | HMAC-SM3(key, msg)，与 HS256 结构相同 |
| SM4    | 对称   | SM4-CBC 加密取最后分组作 MAC          |
| SM2    | 非对称 | SM3哈希 + SM2椭圆曲线签名             |
| RS256  | 非对称 | SHA-256哈希 + RSA私钥签名             |

## 1. 集成及配置说明

### 环境依赖
本工程依赖环境及包结构基于 `uv` 管理。
* **Python** >= 3.12
* **核心依赖**：`PyJWT[crypto]`, `gmssl`, `cryptography`
* **Web依赖**：当配合框架鉴权时需要 `fastapi`

如果作为应用级子模块引入，确保您的代码执行前注册国密算法集：

```python
from py_jwt_helper.jwt.extensions import register_sm_crypto_algorithms

# 推荐在应用生命周期早期的全局位置（如 __init__.py 或 main.py 顶部）调用一次算法注册
register_sm_crypto_algorithms()
```

## 2. 算法支持与 JWT 使用说明

所有的密钥结构，无论是对称短密钥还是非对称长私钥，为便于统一储存在配置和代码传输流中，**全部使用基于 UTF-8 解码的 Base64 字符串格式进行传递**。

### 2.1 密钥 / 公私钥生成

您可以快速使用 `JwtHelper` 根据算法自适应生成高质量强随机校验密钥（均为 Base64 字符串形式）：

```python
from py_jwt_helper import JwtHelper

# 对称算法生成 (HS256, SM3, SM4)
sm4_key_b64 = JwtHelper.generate_key_or_keypair("SM4")
# 输出类似 "c2VjcmV0MWtleXZhbHVlMTI=" 的单一 Base64 字符串

# 非对称算法生成 (RS256, SM2)
# 分别返回包含 "private_key" 和 "public_key" 键值的字典，其内容同样是 Base64 字符串
sm2_keys = JwtHelper.generate_key_or_keypair("SM2")
private_key = sm2_keys["private_key"]
public_key = sm2_keys["public_key"]

# 基于已有的私钥提取对应的公钥 Base64
derived_pub_key = JwtHelper.get_public_key_from_private(private_key, alg="SM2")
```

### 2.2 生成 JWT 令牌 (Create)

使用 `create_jwt` 静态方法，您无需关心底层复杂的头和过期逻辑组装，只需按需传入 `expire_second` 即可：

```python
token = JwtHelper.create_jwt(
    secret_key=private_key, # 对于对称算法传普通key，针对非对称算法传私钥
    iss="sys_a",            # 可选参数，签发者身份（可用于后续路由配置）
    sub="user_001",         # JWT的主题内容或标识
    expire_second=3600,     # 有效期：1小时
    alg="SM2",               # 指定具体签名算法，默认为 "HS256"，当前支持 "HS256", "RS256", "SM3", "SM2", "SM4"五种。
    kid="user_001"          # 可选参数，用于标识密钥，方便从jwk列表中提取密钥
)
```

### 2.3 解析提取与验签 (Verify & Extract)

为了应对不同场景，我们分级提供了如下三种方法：
1. **`JwtHelper.verify_jwt(token, secret_key)`**: 对令牌和签名进行防篡改与时效性的验证。验证不通过则必定抛出对应异常（`PyJWTError` 等），验证通过则返回内部字典封装实体 `JwtPayload`。
2. **`JwtHelper.extract_payload(token)`**: 忽略验证签名和过时检查，强行直接将明文内容抽取为 `JwtPayload`。

**关于 `JwtPayload` 实体**: 
它完美兼容字典获取属性 `payload.get('key')`，且专门提供了面向时间的便捷包装器：

```python
from py_jwt_helper import JwtPayload
from py_jwt_helper import JwtHelper

payload: JwtPayload = JwtHelper.verify_jwt(token, secret_key=public_key)

print(payload.iss)       # 签发方，对应 'sys_a'
print(payload.sub)       # 主题内容，对应 'user_001'
print(payload.exp_time)  # 返回 python 标准的 datetime 对象 (UTC 时区)
print(payload.iat_time)  # 签发时间 (datetime 对象)
print(payload.nbf_time)  # 生效时间 (datetime 对象)
print(payload.get("user_id")) # 获取挂载的其他业务字典内容
```

## 3. 结合 FastAPI 的依赖注入使用

本辅助库已内置为多系统（SysCode）签发隔离鉴权的解决方案，能够自动从请求中捕获密钥标识和 Token 并执行配置匹配的开箱验签能力。

### 3.1 工作流解析机制
当 `JwtAuthDependency` 作为依赖被 FastAPI 端点加载时：
1. **寻找标识 (SysCode)**：依次尝试在 **URL 参数 `jwtSysCode`** -> **Request Header `JWT-SYSCODE`** -> **解析但不验签 JWT 其内部的 `iss`**。
2. **寻找令牌 (Token)**：依次尝试在 **URL 参数 `jwt`** -> **Request Header `Authorization` (兼容自动剔除 `Bearer ` 前缀)** 查找。
3. **验签拦截 (Verify)**：根据标识映射到提前准备好的动态配置以获得 `secret_key`。将以此直接验证 `Token` 并把 `JwtPayload` 安全向下传递；若存在假冒篡改或过期，将直接返回拦截，附带 `HTTP 401 Unauthorized` 状态给客户端。

### 3.2 实际注入示例代码

```python
from fastapi import FastAPI, Depends
from py_jwt_helper import JwtAuthDependency, JwtPayload
from py_jwt_helper.jwt.extensions import register_sm_crypto_algorithms

# 在应用生命周期早期的全局位置（如 __init__.py 或 main.py 顶部）调用一次算法注册
register_sm_crypto_algorithms()

app = FastAPI()

# 1. 准备配置回调函数。此函数常配合读取您的 yaml/json 全局配置文件
def get_auth_config(token: str):
    return {
        # 直接使用字符串映射
        "sys_a": "Base64...Secret...==",
        "sys_b": "Base64...Secret...==",
        
        # 若需要支持默认缺省缺口，可以指定 'default' 键。
        "default": "Base64...Default...=="
    }

# 2. 实例化依赖器
auth_dependency = JwtAuthDependency(jwt_parse_config_callable=get_auth_config)

# 3. 将其注入到对应的端点路由中即可
@app.get("/api/user/profile")
async def get_user_profile(payload: JwtPayload = Depends(auth_dependency)):
    # 当能够走进这行代码时，说明验签已被完全放行，Payload 100% 具备合法性。
    return {"status": "success", "user_sub": payload.sub, "exp": payload.exp_time}
```

任何因过期、错误配置或恶意篡改（不同 SysCode 的串用）的请求都会被安全且安静的直接封锁，无需编写额外的检查逻辑！
