2.5 KiB
2.5 KiB
import json
import hashlib
import base64
from typing import Any, Dict
def build_sign(params: Dict[str, Any], secret_key: str) -> str:
"""
生成签名
:param secret_key: 交易密钥
:return: 计算得到的sign值
"""
# 1. 剔除值为None的键值对,并处理嵌套对象
def process_value(value: Any) -> str:
if isinstance(value, dict):
# 处理对象:过滤null,排序键
filtered_obj = {k: v for k, v in value.items() if v is not None}
# 按键排序
sorted_keys = sorted(filtered_obj.keys())
sorted_obj = {k: filtered_obj[k] for k in sorted_keys}
# 序列化为紧凑JSON
return json.dumps(sorted_obj, separators=(',', ':'), ensure_ascii=False)
elif isinstance(value, (list, tuple)):
# 列表/元组,直接序列化为紧凑JSON
return json.dumps(value, separators=(',', ':'), ensure_ascii=False)
else:
# 基本类型:字符串、数字、布尔
return str(value)
# 对顶层参数进行相同的处理:剔除值=null/空,剔除key="sign",并处理嵌套对象
filtered_params = {}
for key, value in params.items():
if value is None or value == "" or key == "sign":
continue
filtered_params[key] = process_value(value)
# 2. 按键ASCII升序排序
sorted_keys = sorted(filtered_params.keys())
# 3. 拼接成 stringA:key1=value1&key2=value2&...
stringA_parts = []
for key in sorted_keys:
value = filtered_params[key]
# 值如果是字符串,直接使用;否则(理论上不会)转换为字符串
stringA_parts.append(f"{key}={value}")
stringA = "&".join(stringA_parts)
# 4. 追加 &key=密钥
sign_str = stringA + f"&key={secret_key}"
# 5. MD5运算
md5_hash = hashlib.md5(sign_str.encode('utf-8')).digest()
# 6. 转小写(MD5结果通常是十六进制字符串,这里需要先转十六进制再小写)
md5_hex = md5_hash.hex().lower()
# 7. Base64编码
sign = base64.b64encode(md5_hex.encode('utf-8')).decode('utf-8')
return sign
# 示例用法
if __name__ == "__main__":
# 假设请求参数如下
params = {
"reqSerialNo": "20260318110810747",
"data": {
"merchantId": "******",
"applyAmount": 10000,
"reqId": "******",
}
}
secret_key = "******" # 替换为实际的交易密钥
sign = build_sign(params, secret_key)
print(sign)