PyJWT:Python 中的 JSON Web Token 实现
【免费下载链接】pyjwt JSON Web Token implementation in Python 项目地址: https://gitcode.com/gh_mirrors/py/pyjwt
什么是 JWT?
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。这种信息可以被验证和信任,因为它是数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
JWT 的结构
JWT 由三部分组成,用点(.)分隔:
header.payload.signature
PyJWT 核心功能
PyJWT 是一个功能完整的 Python JWT 实现,支持多种加密算法和高级功能:
支持的算法
| 算法类型 | 算法名称 | 说明 | 依赖 |
|---|---|---|---|
| 对称加密 | HS256, HS384, HS512 | HMAC with SHA | 无 |
| 非对称加密 | RS256, RS384, RS512 | RSA with SHA | cryptography |
| 非对称加密 | ES256, ES384, ES512 | ECDSA with SHA | cryptography |
| 非对称加密 | PS256, PS384, PS512 | RSASSA-PSS with SHA | cryptography |
| 非对称加密 | EdDSA | Ed25519/Ed448 | cryptography |
基本用法
import jwt
from datetime import datetime, timedelta, timezone
# 创建 JWT 令牌
payload = {
"user_id": 12345,
"username": "john_doe",
"exp": datetime.now(tz=timezone.utc) + timedelta(hours=1),
"iat": datetime.now(tz=timezone.utc)
}
# 使用 HS256 算法编码
secret_key = "your-secret-key"
token = jwt.encode(payload, secret_key, algorithm="HS256")
print(f"生成的 JWT: {token}")
# 解码和验证
try:
decoded = jwt.decode(token, secret_key, algorithms=["HS256"])
print(f"解码后的数据: {decoded}")
except jwt.ExpiredSignatureError:
print("令牌已过期")
except jwt.InvalidTokenError as e:
print(f"无效令牌: {e}")
高级功能详解
1. 注册声明(Registered Claims)
PyJWT 支持所有标准 JWT 注册声明:
# 完整的注册声明示例
payload = {
# 签发者
"iss": "https://your-api.com",
# 主题(用户ID)
"sub": "user_123456",
# 受众
"aud": ["https://api.example.com", "https://app.example.com"],
# 过期时间(1小时后)
"exp": datetime.now(tz=timezone.utc) + timedelta(hours=1),
# 生效时间(现在生效)
"nbf": datetime.now(tz=timezone.utc),
# 签发时间
"iat": datetime.now(tz=timezone.utc),
# JWT ID(唯一标识符)
"jti": "unique_token_id_123",
# 自定义声明
"custom_data": {
"role": "admin",
"permissions": ["read", "write", "delete"]
}
}
2. 多种密钥类型支持
PyJWT 支持多种密钥格式:
# HMAC 对称密钥
hmac_secret = "super-secret-key"
# RSA 密钥对
private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAwhvqCC+37A+UXgcvDl+7nbVjDI3QErdZBkI1VypVBMkKKWHM
NLMdHk0bIKL+1aDYTRRsCKBy9ZmSSX1pwQlO/3+gRs/MWG27gdRNtf57uLk1+lQI
-----END RSA PRIVATE KEY-----"""
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwhvqCC+37A+UXgcvDl+7
nbVjDI3QErdZBkI1VypVBMkKKWHMNLMdHk0bIKL+1aDYTRRsCKBy9ZmSSX1pwQlO
-----END PUBLIC KEY-----"""
# ECDSA 密钥
ec_private_key = """-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHAhM7P6HG3LgkDvgvfDeaMA6uELj+jEKWsSeOpS/SfYoAoGCCqGSM49
-----END EC PRIVATE KEY-----"""
ec_public_key = """-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXHVxB7s5SR7I9cWwry/JkECIReka
-----END PUBLIC KEY-----"""
3. 完整的验证选项
# 高级验证配置
options = {
"verify_signature": True, # 验证签名
"verify_exp": True, # 验证过期时间
"verify_nbf": True, # 验证生效时间
"verify_iat": True, # 验证签发时间
"verify_aud": True, # 验证受众
"verify_iss": True, # 验证签发者
"require": ["exp", "iat"] # 必须包含的声明
}
decoded = jwt.decode(
token,
key=public_key,
algorithms=["RS256"],
options=options,
audience="https://api.example.com",
issuer="https://your-api.com",
leeway=30 # 30秒宽容时间
)
安全最佳实践
1. 密钥管理
import os
from cryptography.hazmat.primitives import serialization
# 安全地生成和存储密钥
def generate_secure_key():
# 使用足够长度的随机密钥
return os.urandom(32) # 256位密钥
# 对于生产环境,使用环境变量或密钥管理系统
secret_key = os.environ.get("JWT_SECRET_KEY", generate_secure_key())
2. 算法选择指南
3. 防止常见攻击
# 防止算法混淆攻击
# 永远不要根据令牌头中的算法来选择验证算法
def safe_decode(token, public_key):
# 硬编码允许的算法列表
allowed_algorithms = ["RS256", "ES256"]
# 获取未验证的头部信息
header = jwt.get_unverified_header(token)
# 检查算法是否在允许列表中
if header.get("alg") not in allowed_algorithms:
raise jwt.InvalidAlgorithmError("不支持的算法")
return jwt.decode(token, public_key, algorithms=allowed_algorithms)
实际应用场景
1. Web 应用认证
from flask import request, jsonify
import jwt
from functools import wraps
def jwt_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
if not token:
return jsonify({"error": "缺少认证令牌"}), 401
try:
# 验证令牌
payload = jwt.decode(
token,
os.environ['JWT_SECRET'],
algorithms=["HS256"],
audience="web-app",
issuer="auth-service"
)
request.user = payload
except jwt.ExpiredSignatureError:
return jsonify({"error": "令牌已过期"}), 401
except jwt.InvalidTokenError:
return jsonify({"error": "无效令牌"}), 401
return f(*args, **kwargs)
return decorated_function
@app.route('/protected')
@jwt_required
def protected_route():
return jsonify({"message": "访问成功", "user": request.user})
2. API 微服务间认证
import requests
from jwt import PyJWKClient
class APIClient:
def __init__(self, jwks_url):
self.jwks_client = PyJWKClient(jwks_url)
def make_authenticated_request(self, url, token):
# 从 JWKS 端点获取签名密钥
signing_key = self.jwks_client.get_signing_key_from_jwt(token)
# 验证令牌
try:
payload = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
audience="api-service",
options={"verify_exp": True}
)
# 添加认证头
headers = {
"Authorization": f"Bearer {token}",
"X-User-ID": payload["sub"]
}
response = requests.get(url, headers=headers)
return response.json()
except jwt.InvalidTokenError as e:
raise Exception(f"认证失败: {e}")
3. 分布式会话管理
class JWTSessionManager:
def __init__(self, secret_key, algorithm="HS256"):
self.secret_key = secret_key
self.algorithm = algorithm
def create_session(self, user_id, user_data, expires_in=3600):
payload = {
"sub": user_id,
"user": user_data,
"exp": datetime.now(tz=timezone.utc) + timedelta(seconds=expires_in),
"iat": datetime.now(tz=timezone.utc),
"jti": str(uuid.uuid4()) # 防止重放攻击
}
return jwt.encode(payload, self.secret_key, algorithm=self.algorithm)
def validate_session(self, token):
try:
payload = jwt.decode(
token,
self.secret_key,
algorithms=[self.algorithm],
options={
"verify_exp": True,
"verify_iat": True
}
)
# 检查令牌是否在黑名单中(防止注销后继续使用)
if self.is_token_revoked(payload["jti"]):
raise jwt.InvalidTokenError("令牌已被撤销")
return payload
except jwt.InvalidTokenError:
return None
def revoke_token(self, token):
# 将令牌ID加入黑名单
payload = jwt.decode(token, self.secret_key, options={"verify_signature": False})
self.blacklist.add(payload["jti"])
性能优化技巧
1. 密钥重用
# 对于RSA密钥,重复使用密钥对象以提高性能
from cryptography.hazmat.primitives import serialization
# 一次性加载密钥
private_key = serialization.load_pem_private_key(
private_key_bytes,
password=None,
backend=default_backend()
)
# 重复使用同一个密钥对象
def encode_multiple_tokens(payloads):
tokens = []
for payload in payloads:
token = jwt.encode(payload, private_key, algorithm="RS256")
tokens.append(token)
return tokens
2. 批量验证
def batch_verify_tokens(tokens, public_key):
valid_tokens = []
for token in tokens:
try:
# 快速验证签名(不验证声明)
header = jwt.get_unverified_header(token)
jwt.decode(token, public_key, algorithms=[header["alg"]], options={"verify_exp": False})
valid_tokens.append(token)
except jwt.InvalidTokenError:
continue
return valid_tokens
错误处理和监控
import logging
from prometheus_client import Counter
# 监控指标
jwt_validation_errors = Counter('jwt_validation_errors', 'JWT验证错误', ['error_type'])
class JWTValidator:
def __init__(self, secret_key):
self.secret_key = secret_key
self.logger = logging.getLogger(__name__)
def validate(self, token):
try:
payload = jwt.decode(
token,
self.secret_key,
algorithms=["HS256"],
options={
"verify_exp": True,
"verify_iat": True,
"verify_aud": True
}
)
return payload
except jwt.ExpiredSignatureError:
self.logger.warning("JWT令牌已过期")
jwt_validation_errors.labels(error_type='expired').inc()
raise
except jwt.InvalidAudienceError:
self.logger.warning("无效的受众声明")
jwt_validation_errors.labels(error_type='invalid_audience').inc()
raise
except jwt.InvalidIssuerError:
self.logger.warning("无效的签发者")
jwt_validation_errors.labels(error_type='invalid_issuer').inc()
raise
except jwt.InvalidTokenError as e:
self.logger.error(f"无效令牌: {e}")
jwt_validation_errors.labels(error_type='invalid_token').inc()
raise
总结
PyJWT 是一个强大而灵活的 Python JWT 实现,为现代 Web 应用和微服务架构提供了完整的认证解决方案。通过遵循本文中的最佳实践和安全指南,您可以构建安全、高效且可扩展的认证系统。
关键要点:
- 选择合适的算法:根据安全需求选择对称或非对称加密
- 正确使用声明:充分利用标准声明增强安全性
- 实施严格验证:配置完整的验证选项防止常见攻击
- 监控和错误处理:建立完善的监控和错误处理机制
- 性能优化:重用密钥对象,批量处理提高性能
通过合理使用 PyJWT,您可以为您的应用程序构建一个既安全又高效的认证体系。
【免费下载链接】pyjwt JSON Web Token implementation in Python 项目地址: https://gitcode.com/gh_mirrors/py/pyjwt
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



