Skip to content

签名规则

示例参数

json
{
    "PayChannelId": "test",
    "OrderNo": "test0001",
    "Amount": "100",
    "GoodsName": null,
    "Payer": "username",
    "PayerNo": null,
    "PayerAddress": null,
    "Ext": "ext",
    "CallbackUrl": "https://www.google.com",
    "AccessKey": "dTBTLXiFRZqcUMRRH43HTA",
    "Timestamp": 1655997727
}

拼接待签名字符串

  1. 获取除 Sign 外所有参数。
  2. 将所有参数按名称进行 ASCII 升序排序,再以 key=value 的形式拼接参数名和参数值(空值不参与签名,不加入签名串),多个参数对之间用 & 符号连接。 示例密钥:vXtWZxBHDDLCOFaa6vwwTV3Nr-W87TIZqdvHyxk
  3. 将2中获取到的字符串拼接&SecretKey=MD5密钥,得到以下字符串。
AccessKey=dTBTLXiFRZqcUMRRH43HTA&Amount=100&CallbackUrl=https://www.google.com&Ext=ext&OrderNo=test0001&PayChannelId=test&Payer=username&Timestamp=1655997727&SecretKey=vXtWZxBHDDLCOFaa6vwwTV3Nr-W87TIZqdvHyxk

生成签名

对拼接后的字符串用MD5算法生成签名,小写

得到签名

96907844ea7b2fd4c5903c747e13db98

签名demo

java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.StringJoiner;
/**
* 签名生成
*
* @param map 待加密参数
* @param key 密钥
* @return 签名字符串
*/
private static String generateSign(Map<String, Object> map, String key) throws NoSuchAlgorithmException {
    StringJoiner sj = new StringJoiner("&");
    map.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(x -> {
                if (x.getValue() != null && !x.getValue().toString().isEmpty()) {
                    sj.add(x.getKey() + "=" + x.getValue());
                }
            });
    String rawString = sj.toString() + "&SecretKey=" + key;
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] array = md.digest(rawString.getBytes(StandardCharsets.UTF_8));
    StringBuilder sb = new StringBuilder();
    for (byte item : array) {
        sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
    }
    return sb.toString();
}
go
import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"sort"
	"strings"
)

func GenerateMD5Sign(key string, param map[string]interface{}) string {
	keys := make([]string, 0, len(param))
	for k := range param {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	var pairs []string
	for _, k := range keys {
		valStr := fmt.Sprint(param[k])
		if valStr != "" {
			pairs = append(pairs, k+"="+valStr)
		}
	}
	signStr := strings.Join(pairs, "&")
	signStr += "&SecretKey=" + key

	hash := md5.New()
	hash.Write([]byte(signStr))
	return hex.EncodeToString(hash.Sum(nil))
}
csharp
public class Utils {
    public static string GenSign(object body, string secret) {
        var p = body.GetType().GetProperties();
        var kp = new SortedDictionary<string, string>();

        foreach (var item in p) {
            if ("sign".Equals(item.Name, StringComparison.OrdinalIgnoreCase)) continue;
            kp.Add(item.Name, $"{item.GetValue(body, null)}");
        }
        var str = string.Join("&", kp.Where(t => !string.IsNullOrWhiteSpace(t.Value)).Select(t => $"{t.Key}={t.Value}")) + "&SecretKey=" + secret;
        Console.WriteLine($"gen sign str: {str}");

        using var md5 = MD5.Create();
        return Convert.ToHexString(md5.ComputeHash(Encoding.UTF8.GetBytes(str))).ToLower();
    }
}
php
<?php

class Utils {
    /**
     * 签名生成
     * @param array $body 待加密参数
     * @param string $secret 密钥
     * @return string 签名字符串
     */
    public static function genSign($body, $secret) {
        unset($body['sign']);
        ksort($body);

        $pairs = [];
        foreach ($body as $k => $v) {
            if ($v !== '' && $v !== null) {
                $pairs[] = "$k=$v";
            }
        }

        $signStr = implode('&', $pairs) . "&SecretKey=" . $secret;
        return md5($signStr);
    }
}