PyJWT:Python 中的 JSON Web Token 实现

PyJWT:Python 中的 JSON Web Token 实现

【免费下载链接】pyjwt JSON Web Token implementation in Python 【免费下载链接】pyjwt 项目地址: https://gitcode.com/gh_mirrors/py/pyjwt

什么是 JWT?

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。这种信息可以被验证和信任,因为它是数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。

JWT 的结构

JWT 由三部分组成,用点(.)分隔:

header.payload.signature

mermaid

PyJWT 核心功能

PyJWT 是一个功能完整的 Python JWT 实现,支持多种加密算法和高级功能:

支持的算法

算法类型算法名称说明依赖
对称加密HS256, HS384, HS512HMAC with SHA
非对称加密RS256, RS384, RS512RSA with SHAcryptography
非对称加密ES256, ES384, ES512ECDSA with SHAcryptography
非对称加密PS256, PS384, PS512RSASSA-PSS with SHAcryptography
非对称加密EdDSAEd25519/Ed448cryptography

基本用法

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. 算法选择指南

mermaid

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 应用和微服务架构提供了完整的认证解决方案。通过遵循本文中的最佳实践和安全指南,您可以构建安全、高效且可扩展的认证系统。

关键要点:

  1. 选择合适的算法:根据安全需求选择对称或非对称加密
  2. 正确使用声明:充分利用标准声明增强安全性
  3. 实施严格验证:配置完整的验证选项防止常见攻击
  4. 监控和错误处理:建立完善的监控和错误处理机制
  5. 性能优化:重用密钥对象,批量处理提高性能

通过合理使用 PyJWT,您可以为您的应用程序构建一个既安全又高效的认证体系。

【免费下载链接】pyjwt JSON Web Token implementation in Python 【免费下载链接】pyjwt 项目地址: https://gitcode.com/gh_mirrors/py/pyjwt

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值