python 设计出一套接口签名和验证

需要app_id、secret 需要提前准备好作为密钥

生成签名函数

import hmac, hashlib, json


def generate_signature(http_method, uri_path, args, body, secret):
    """
    生成签名的函数。
    :param http_method: HTTP方法,例如"GET"或"POST"

    :param uri_path: 请求的URI路径
    :param args: 请求的参数(字典形式)
    :param secret: 用于生成签名的密钥(字节类型)
    :return: 生成的签名(十六进制字符串形式)
    """
    # 将HTTP方法转换为大写
    http_method = http_method.upper()
    if not body:
        content_md5 = ''
    else:
        # 请求内容的MD5哈希值
        content_md5 = hashlib.md5(json.dumps(body).encode('utf-8')).hexdigest()
    # 将请求参数按键名排序并生成参数字符串
    keys = sorted(args.keys())
    args_to_sign = []

    for k in keys:
        v = args.get(k, '')
        if isinstance(v, (list, tuple)) and len(v) > 0:
            v = v[0]
        args_to_sign.append(f"{k}={v}")

    # 如果有参数,拼接成query string格式
    if args_to_sign and len(args_to_sign) > 0:
        args_to_sign = '?' + '&'.join(args_to_sign)
    else:
        args_to_sign = ''

    # 生成待签名的字符串
    string_to_sign = f"{http_method}\n{content_md5}\n{uri_path}{args_to_sign}"

    # 生成签名
    signed = hmac.new(secret, string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()

    # print("string_to_sign:", string_to_sign)
    return signed

 

验证函数

# -*- coding: utf8 -*-
"""
梦美奇为内部其他服务提供接口如:趣作图 需要做签名认证
"""
import hmac, hashlib, json
from flask import request
from web_app.models.developer import DeveloperApp


def generate_signature(http_method, uri_path, args, body, secret):
    """
    生成签名的函数。
    :param http_method: HTTP方法,例如"GET"或"POST"

    :param uri_path: 请求的URI路径
    :param args: 请求的参数(字典形式)
    :param secret: 用于生成签名的密钥(字节类型)
    :return: 生成的签名(十六进制字符串形式)
    """

    # 将HTTP方法转换为大写
    http_method = http_method.upper()
    # 请求内容的MD5哈希值
    if not body:
        content_md5 = ""
    else:
        content_md5 = hashlib.md5(body).hexdigest()
    # 将请求参数按键名排序并生成参数字符串
    keys = sorted(args.keys())
    args_to_sign = []

    for k in keys:
        v = args.get(k, '')
        if isinstance(v, (list, tuple)) and len(v) > 0:
            v = v[0]
        args_to_sign.append(f"{k}={v}")

    # 如果有参数,拼接成query string格式
    if args_to_sign and len(args_to_sign) > 0:
        args_to_sign = '?' + '&'.join(args_to_sign)
    else:
        args_to_sign = ''

    # 生成待签名的字符串
    string_to_sign = f"{http_method}\n{content_md5}\n{uri_path}{args_to_sign}"

    # 生成签名
    signed = hmac.new(secret, string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()

    return signed, string_to_sign


def very_signature(http_method, uri_path, args, body, wx_app_id, wx_sign):
    """
    验证签名
    :param http_method:
    :param uri_path:
    :param args:
    :param secret:
    :param signature:
    :return:
    """
    developer_app = DeveloperApp.get_by_app_id(wx_app_id)

    if not developer_app or not developer_app.secret:
        return False
    secret = developer_app.secret

    # 确保密钥是字节串
    if isinstance(secret, str):
        secret = secret.encode('utf-8')

    sign, string_to_sign = generate_signature(http_method, uri_path, args, body, secret)
    if request.wx_request_debug:
        print("string_to_sign:", string_to_sign)
        print("wx_sign:", wx_sign, "sign:", sign)

    return wx_sign == sign


if __name__ == '__main__':
    very_signature(request.method, request.path, args=request.values, body=request.get_data(), wx_app_id="wx_appid",
                   wx_sign="wx_sign")

 

posted on 2024-09-03 12:17  星河赵  阅读(51)  评论(0编辑  收藏  举报

导航