大家好,我是木木。
今天给大家分享一个偏 JWT 令牌处理方向的 Python 库,pyjwt。
它把 JSON Web Token 的编码、解码、声明校验和多种签名算法统一到一套 API 里,适合做登录态令牌、服务间鉴权、OIDC 接入,以及各种“我需要安全地收发 JWT” 的 Python 场景。
项目地址:https://github.com/jpadilla/pyjwt官方文档:https://pyjwt.readthedocs.io/en/stable/
三大特点
基础用法特别顺手
如果你只是想快速把一段 payload 编成 token,再在服务端校验回来,PyJWT 的 jwt.encode 和 jwt.decode 已经足够顺手。对登录态、内部接口 token、回调签名这些常见需求来说,几行代码就能把流程跑通。
对标准声明校验支持完整
JWT 真正容易出问题的地方,不是“能不能编码”,而是 exp、iss、aud、sub 这些声明有没有统一校验。PyJWT 内置了这些能力,也支持 require 约束,让你更容易把规则收进一处,而不是散在业务代码里。
算法和接入层能力都够用
除了最常见的 HS256,文档里还能看到 RS256、PS256、ES256、EdDSA、JWKS、OIDC 登录流这些能力。也就是说,它不只是一个“把字典转字符串”的工具,更像一层 JWT 协议实现。
最佳实践
安装方式:pip install PyJWT
如果你要用 RSA / ECDSA / EdDSA 这类非对称算法,建议直接安装:pip install PyJWT[crypto]
功能一:用 HS256 生成并校验一个最基础的业务 token
这段代码解决什么问题:很多项目刚开始接 JWT,并不是要上来就做 OIDC 或 JWKS,而是先把“用户身份 + 角色 + 过期时间”塞进 token,并且在服务端稳定解出来。这个场景用 HS256 最常见,PyJWT 的调用也最直接。
fromdatetimeimportdatetime,timezoneimportjwtkey="0123456789abcdef0123456789abcdef"payload={"sub":"user-1001","role":"editor","exp":datetime(2030,1,1,tzinfo=timezone.utc),}token=jwt.encode(payload,key,algorithm="HS256")decoded=jwt.decode(token,key,algorithms=["HS256"])print("token:",token)print("sub:",decoded["sub"])print("role:",decoded["role"])print("exp type:",type(decoded["exp"]).__name__)
这里有两个实用点。第一,datetime 可以直接作为 exp 传进去,不用你手动转 Unix 时间戳。第二,解码后 sub、role、exp 都已经回到统一的 claim 结构里,非常适合作为登录态或内部接口认证的基础写法。
功能二:把 issuer、audience 和必需声明一起校验掉
这段代码解决什么问题:JWT 上线以后,真正危险的常常不是“token 伪造”,而是不同服务拿着一个 token 就默认能用,没人统一校验它是不是这个签发方发的、是不是发给这个系统的、是不是少了关键声明。PyJWT 可以把这些规则集中放在 decode 里处理。
importjwtkey="0123456789abcdef0123456789abcdef"payload={"sub":"job-sync-42","iss":"https://auth.example.com","aud":"daily-awesome-python","iat":1700000000,"exp":1893456000,}token=jwt.encode(payload,key,algorithm="HS256",headers={"kid":"sync-key-1"})header=jwt.get_unverified_header(token)decoded=jwt.decode(token,key,audience="daily-awesome-python",issuer="https://auth.example.com",algorithms=["HS256"],options={"require":["exp","iss","sub"]},)print("kid:",header["kid"])print("iss:",decoded["iss"])print("aud:",decoded["aud"])print("sub:",decoded["sub"])
这类写法很适合服务拆分以后统一做认证网关或中间件。你不再只是“能 decode 出来就算合法”,而是把签发方、接收方和关键声明都收成显式约束。后面要做多租户、多环境或者多 key 轮换时,代码结构也会更清楚。
功能三:用 RS256 给服务账号令牌签名并校验
这段代码解决什么问题:对外服务、内部网关或者和第三方身份系统对接时,很多场景都会用非对称签名。对这种场景来说,重点不只是“token 能生成”,而是私钥签发、公钥校验的流程能不能稳定落地。PyJWT 搭配 cryptography 就能把这件事做完整。
importjwtfromcryptography.hazmat.primitivesimportserializationfromcryptography.hazmat.primitives.asymmetricimportrsaprivate_key_obj=rsa.generate_private_key(public_exponent=65537,key_size=2048)private_key=private_key_obj.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption(),)public_key=private_key_obj.public_key().public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo,)token=jwt.encode({"sub":"service-account","scope":"publish:wechat","iss":"daily-python"},private_key,algorithm="RS256",)decoded=jwt.decode(token,public_key,algorithms=["RS256"],issuer="daily-python")print("alg:",jwt.get_unverified_header(token)["alg"])print("sub:",decoded["sub"])print("scope:",decoded["scope"])print("token prefix:",token.split(".")[0])
这个场景对接 OIDC、企业身份平台或者服务账号体系时特别常见。非对称签名的好处是签发和校验可以分离,你把私钥留在签发端,把公钥分发给校验端,部署边界会比共享对称密钥清晰很多。
环境与版本信息
高级功能
PyJWT 不只是本地 encode / decode。官方文档里还有 PyJWKClient,可以直接从 JWKS 地址拉公钥并按 kid 自动匹配,这一点在 Auth0、Okta、OIDC Provider 这类接入里很实用。你不需要把一堆 PEM 公钥硬编码在项目里,而是可以按标准方式从远端密钥集获取。
另外,文档里也专门提到了 key length validation、required claims、读取未校验 header、OIDC 登录流中的 at_hash 校验。这些能力说明 PyJWT 更适合被放在认证基础设施层,而不只是做一个“登录成功后顺手塞 token”的小工具。
适用场景
- Web 登录态、接口访问令牌、服务间调用这类典型 JWT 场景
- 需要统一校验
exp、iss、aud、sub 等标准声明的项目 - 要接 OIDC / JWKS / 第三方身份平台的 Python 服务
- 需要同时支持 HS256 和 RS256 等多种签名方案的团队
不适用场景
- 你其实不需要 JWT,只要一个普通 session 或随机 API Key 就够了
- 项目完全不想处理签名算法、声明约束和 token 生命周期,只想拿现成身份平台 SDK
- 需要的是完整认证框架、用户管理后台和授权页面,而不是 JWT 协议层能力
- 团队还没有统一 token 签发和校验策略,准备直接在多个服务里各写一套规则
上线检查
- 明确区分对称密钥和非对称密钥场景,不要把 HS256 和 RS256 的用法混在一起。
- 把
iss、aud、exp、sub 这类声明校验收口到统一中间层,别在各个接口里各写各的。 - 如果接 OIDC 或远端 JWKS,提前规划好 key 轮换、缓存策略和
kid 对应关系。
总结
PyJWT 的好用,不在于它把 JWT 变得“很神秘”,而在于它把本来容易写散、写错的那层协议细节收得很规整。要是你的项目已经进入“token 需要长期维护、统一校验、可扩展签名算法”的阶段,它会非常顺手。