Python签名校验案例如何封装签名验证

wen python案例 31

本文目录导读:

Python签名校验案例如何封装签名验证

  1. 基础签名校验封装
  2. RSA 签名校验封装
  3. API请求签名校验封装
  4. 使用示例
  5. 装饰器实现

我来为您提供几种Python签名校验的封装方案,从基础到进阶:

基础签名校验封装

HMAC-SHA256 签名方案

import hmac
import hashlib
import base64
import json
from typing import Dict, Any, Optional
from datetime import datetime
class HMACSignatureValidator:
    """HMAC-SHA256签名校验器"""
    def __init__(self, secret_key: str):
        """
        初始化签名校验器
        :param secret_key: 密钥
        """
        self.secret_key = secret_key.encode('utf-8')
    def generate_signature(self, data: Dict[str, Any], timestamp: Optional[int] = None) -> str:
        """
        生成签名
        :param data: 待签名数据
        :param timestamp: 时间戳(可选)
        :return: 签名字符串
        """
        # 添加时间戳
        if timestamp is None:
            timestamp = int(datetime.now().timestamp())
        data['timestamp'] = timestamp
        # 序列化并排序
        message = json.dumps(data, sort_keys=True, ensure_ascii=False)
        # 计算签名
        signature = hmac.new(
            self.secret_key,
            message.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        return signature
    def verify_signature(self, data: Dict[str, Any], signature: str, 
                        time_window: int = 300) -> bool:
        """
        验证签名
        :param data: 原始数据
        :param signature: 待验证签名
        :param time_window: 时间窗口(秒),默认5分钟
        :return: 是否验证通过
        """
        # 检查时间戳
        if 'timestamp' not in data:
            return False
        timestamp = data['timestamp']
        current_time = int(datetime.now().timestamp())
        # 检查时间是否在窗口内
        if abs(current_time - timestamp) > time_window:
            return False
        # 计算期望签名
        expected_signature = self.generate_signature(data, timestamp)
        # 使用hmac.compare_digest防止时序攻击
        return hmac.compare_digest(expected_signature, signature)

RSA 签名校验封装

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import InvalidSignature
import base64
class RSASignatureValidator:
    """RSA签名校验器"""
    def __init__(self, public_key_path: str = None, private_key_path: str = None):
        """
        初始化RSA签名校验器
        :param public_key_path: 公钥文件路径
        :param private_key_path: 私钥文件路径
        """
        self.public_key = None
        self.private_key = None
        if public_key_path:
            self.load_public_key(public_key_path)
        if private_key_path:
            self.load_private_key(private_key_path)
    def load_public_key(self, path: str):
        """加载公钥"""
        with open(path, 'rb') as f:
            self.public_key = serialization.load_pem_public_key(f.read())
    def load_private_key(self, path: str):
        """加载私钥"""
        with open(path, 'rb') as f:
            self.private_key = serialization.load_pem_private_key(
                f.read(),
                password=None
            )
    def generate_signature(self, message: str) -> str:
        """生成RSA签名"""
        if not self.private_key:
            raise ValueError("Private key not loaded")
        signature = self.private_key.sign(
            message.encode('utf-8'),
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        return base64.b64encode(signature).decode('utf-8')
    def verify_signature(self, message: str, signature: str) -> bool:
        """验证RSA签名"""
        if not self.public_key:
            raise ValueError("Public key not loaded")
        try:
            signature_bytes = base64.b64decode(signature)
            self.public_key.verify(
                signature_bytes,
                message.encode('utf-8'),
                padding.PSS(
                    mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=padding.PSS.MAX_LENGTH
                ),
                hashes.SHA256()
            )
            return True
        except InvalidSignature:
            return False
        except Exception as e:
            print(f"Verification error: {e}")
            return False

API请求签名校验封装

import requests
from typing import Dict, Optional
from urllib.parse import urlencode
class APISignatureValidator:
    """API请求签名校验器"""
    def __init__(self, app_id: str, secret_key: str):
        """
        初始化API签名校验器
        :param app_id: 应用ID
        :param secret_key: 密钥
        """
        self.app_id = app_id
        self.secret_key = secret_key
        self.validator = HMACSignatureValidator(secret_key)
    def generate_request_signature(self, http_method: str, url: str, 
                                 params: Dict[str, Any] = None, 
                                 body: Dict[str, Any] = None) -> Dict[str, str]:
        """
        生成API请求签名
        :param http_method: HTTP方法
        :param url: 请求URL
        :param params: 查询参数
        :param body: 请求体
        :return: 包含签名的请求头
        """
        timestamp = int(datetime.now().timestamp())
        nonce = self._generate_nonce()
        # 构建待签名字符串
        signature_data = {
            'app_id': self.app_id,
            'method': http_method.upper(),
            'url': url,
            'timestamp': timestamp,
            'nonce': nonce
        }
        if params:
            signature_data['params'] = sorted(params.items())
        if body:
            signature_data['body'] = json.dumps(body, sort_keys=True)
        # 生成签名
        signature = self.validator.generate_signature(signature_data, timestamp)
        return {
            'X-App-ID': self.app_id,
            'X-Timestamp': str(timestamp),
            'X-Nonce': nonce,
            'X-Signature': signature
        }
    def verify_request_signature(self, headers: Dict[str, str], 
                                http_method: str, url: str,
                                params: Dict[str, Any] = None,
                                body: Dict[str, Any] = None) -> bool:
        """
        验证API请求签名
        :param headers: 请求头
        :param http_method: HTTP方法
        :param url: 请求URL
        :param params: 查询参数
        :param body: 请求体
        :return: 是否验证通过
        """
        try:
            app_id = headers.get('X-App-ID')
            timestamp = int(headers.get('X-Timestamp', '0'))
            nonce = headers.get('X-Nonce')
            signature = headers.get('X-Signature')
            if not all([app_id, timestamp, nonce, signature]):
                return False
            # 构建验证数据
            verify_data = {
                'app_id': app_id,
                'method': http_method.upper(),
                'url': url,
                'timestamp': timestamp,
                'nonce': nonce
            }
            if params:
                verify_data['params'] = sorted(params.items())
            if body:
                verify_data['body'] = json.dumps(body, sort_keys=True)
            # 验证签名
            return self.validator.verify_signature(verify_data, signature)
        except Exception as e:
            print(f"Verification error: {e}")
            return False
    def _generate_nonce(self) -> str:
        """生成随机数"""
        import uuid
        return str(uuid.uuid4())

使用示例

# 1. HMAC签名示例
hmac_validator = HMACSignatureValidator("my_secret_key_123")
# 生成签名
data = {"user_id": 123, "action": "login"}
signature = hmac_validator.generate_signature(data)
print(f"Generated signature: {signature}")
# 验证签名
result = hmac_validator.verify_signature(data, signature)
print(f"Verification result: {result}")
# 2. API请求签名示例
api_validator = APISignatureValidator("app_123", "secret_456")
# 生成请求签名
headers = api_validator.generate_request_signature(
    "POST", 
    "https://api.example.com/user/login",
    body={"username": "test", "password": "pass"}
)
print(f"Request headers: {headers}")
# 验证请求签名
is_valid = api_validator.verify_request_signature(
    headers,
    "POST",
    "https://api.example.com/user/login",
    body={"username": "test", "password": "pass"}
)
print(f"Verification result: {is_valid}")

装饰器实现

from functools import wraps
from flask import request, jsonify
def require_signature(validator):
    """API签名验证装饰器"""
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            # 从请求中获取签名相关信息
            headers = {
                'X-App-ID': request.headers.get('X-App-ID'),
                'X-Timestamp': request.headers.get('X-Timestamp'),
                'X-Nonce': request.headers.get('X-Nonce'),
                'X-Signature': request.headers.get('X-Signature')
            }
            # 验证签名
            if not validator.verify_request_signature(
                headers,
                request.method,
                request.url,
                request.args,
                request.json
            ):
                return jsonify({"error": "Invalid signature"}), 401
            return f(*args, **kwargs)
        return decorated_function
    return decorator
# 使用示例
app = Flask(__name__)
validator = APISignatureValidator("app_123", "secret_456")
@app.route('/api/secure', methods=['POST'])
@require_signature(validator)
def secure_endpoint():
    return jsonify({"message": "Access granted"})

这些封装提供了不同安全级别的签名校验方案,您可以根据具体需求选择合适的方案,建议在生产环境中使用RSA签名,并确保密钥的安全存储。

抱歉,评论功能暂时关闭!