Skip to content

签名算法

所有请求需携带 signature 参数,由以下步骤生成。

生成步骤

  1. 移除 signature 参数(如果存在)
  2. 处理数组参数,将数组 / 对象转换为 JSON 字符串(不进行键排序)
  3. 按键名升序排序所有参数
  4. 拼接参数为 key=value& 格式(跳过空值)
  5. 在末尾追加 &api_secret=你的商户密钥
  6. 对完整字符串进行 MD5 加密并转为大写

最终签名

签名结果为大写的 32 位 MD5 字符串,例如 D866A542EB56BBD26857B552C432E9D6

代码示例

php
function generateSignature($params, $apiSecret) {
    // 1. 移除 signature 参数
    unset($params['signature']);

    // 2. 处理数组参数
    $processedParams = [];
    foreach ($params as $key => $value) {
        if (is_array($value)) {
            $processedParams[$key] = json_encode($value, JSON_UNESCAPED_UNICODE);
        } else {
            $processedParams[$key] = $value;
        }
    }

    // 3. 按键名排序
    ksort($processedParams);

    // 4. 拼接参数
    $stringToSign = '';
    foreach ($processedParams as $key => $value) {
        if ($value !== '' && $value !== null) {
            $stringToSign .= $key . '=' . $value . '&';
        }
    }

    // 5. 移除最后的 & 并追加 api_secret
    $stringToSign = rtrim($stringToSign, '&') . '&api_secret=' . $apiSecret;

    // 6. 生成 MD5 签名并转为大写
    return strtoupper(md5($stringToSign));
}

// 使用示例
$params = [
    'api_key' => 'your_api_key',
    'timestamp' => time(),
    'nonce' => 'random_string_16',
    'order_type' => 1,
    'cny_amount' => 1000.00
];

$apiSecret = 'your_api_secret';
$signature = generateSignature($params, $apiSecret);
$params['signature'] = $signature;
javascript
// 完整的 MD5 + generateSignature 实现 见文档站源码
// 这里给出调用示例
import { generateSignature } from './md5.js'

const params = {
  api_key: 'your_api_key',
  timestamp: Math.floor(Date.now() / 1000),
  nonce: Math.random().toString(36).substring(2, 18),
  order_type: 1,
  cny_amount: 1000.00
}

const apiSecret = 'your_api_secret'
params.signature = generateSignature(params, apiSecret)
python
import hashlib
import json
import time
import random
import string

def generate_signature(params, api_secret):
    # 1. 移除 signature
    params = {k: v for k, v in params.items() if k != 'signature'}

    # 2. 处理数组参数
    processed = {}
    for k, v in params.items():
        if isinstance(v, (dict, list)):
            processed[k] = json.dumps(v, ensure_ascii=False)
        else:
            processed[k] = v

    # 3 & 4. 按键名排序并拼接参数
    parts = []
    for k in sorted(processed.keys()):
        v = processed[k]
        if v != '' and v is not None:
            parts.append(f'{k}={v}')

    # 5. 追加 api_secret
    string_to_sign = '&'.join(parts) + '&api_secret=' + api_secret

    # 6. MD5 大写
    return hashlib.md5(string_to_sign.encode('utf-8')).hexdigest().upper()

# 使用示例
params = {
    'api_key': 'your_api_key',
    'timestamp': str(int(time.time())),
    'nonce': ''.join(random.choices(string.ascii_letters + string.digits, k=16)),
    'order_type': 1,
    'cny_amount': 1000.00
}

api_secret = 'your_api_secret'
params['signature'] = generate_signature(params, api_secret)

验签失败常见原因

  • 参数值被 URL 编码(如中文未解码就参与签名)
  • api_secret 填写错误
  • 空值参数未过滤
  • 数组参数未按 json_encode 序列化(卖单 payment_method)