Skip to content

签名规则

示例参数

json
{
    "time_stamp": "1613719331",
    "mch_no": "1611906847",
    "nonce": "9ZD0fWnWg1VPRlOV",
    "sign": "8cf605c78f09565c84e46389bf0cec6691e6e83b1fd5f78ef8710d6581b4540e",
    "out_order_no": "test0001",
    "amount": "1000",
    "pay_type": "ALI_QR",
    "client_ip": "1.1.1.1",
    "attach": "test",
    "notify_url": "https://www.google.com",
    "currency": "CNY"
}

拼接待签名字符串

  1. 获取除 sign 外所有参数
  2. 将所有参数按名称进行 ASCII 升序排序,再以 key=value 的形式拼接参数名和参数值(空值不参与签名,不加入签名串),多个参数对之间用 & 符号连接,得到以下字符串。
amount=1000&attach=test&client_ip=1.1.1.1&currency=CNY&mch_no=1611906847&nonce=9ZD0fWnWg1VPRlOV&notify_url=https://www.google.com&out_order_no=test0001&pay_type=ALI_QR&time_stamp=1613719331

生成签名

对拼接后的字符串用hmac-sha256算法生成签名(HEX编码,不区分大小写)

示例秘钥

8014d755163742c7a0c26d72a0601e59

得到签名

8cf605c78f09565c84e46389bf0cec6691e6e83b1fd5f78ef8710d6581b4540e

签名demo

java
/**
* 签名生成
*
* @param map 待加密参数
* @param key 密钥
* @return 签名字符串
*/
private static String generateSign(Map < String, Object > map, String key) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
    StringJoiner sj = new StringJoiner("&");
    map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(x - > {
        sj.add(x.getKey() + "=" + x.getValue());
    });
    Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
    SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
    sha256_HMAC.init(secret_key);
    byte[] array = sha256_HMAC.doFinal(sj.toString().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/hmac"
	"encoding/hex"
	"sort"
)

func HmacSHA256(key string, param map[string]string) (string, error) {
	keys := []string{}
	for k := range param {
		keys = append(keys, k)
	}

	sort.Strings(keys)

	pair := []string{}
	for _, k := range keys {
		pair = append(pair, k+"="+param[k])
	}

	signStr := strings.Join(pair, "&")

	h := hmac.New(sha256.New, []byte(key))
	if _, err := h.Write([]byte(signStr)); err != nil {
		return "", err
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}
csharp
using System.Security.Cryptography;
using System.Text;

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)) continue;
      kp.Add(item.Name, $"{item.GetValue(body, null)}");
    }

    var str = string.Join("&", kp.Select(t => !string.IsNullOrWhiteSpace(t.Value) ? $"{t.Key}={t.Value}" : "").Where(t => !string.IsNullOrWhiteSpace(t)));
    Console.WriteLine($"gen sign str: {str}");

    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    return Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes(str))).ToLower();
  }
}
php
<?php
function genSign($arrays,$secret){
    ksort($arrays);
    $str ="";
    $flag = true;
    foreach ($arrays as $key => $value)
    {
        if ($flag) {
        $str = $key."=".$value;
        $flag = false;
        }else {
        $str = $str."&".$key."=".$value;
        }
    }
    $sign = hash_hmac('sha256', $str, $secret);
    return $sign;
}

$arrays = array(
    'time_stamp'=>'1613719331',
    'mch_no'=>'1611906847',
    'nonce'=>'9ZD0fWnWg1VPRlOV',
    'out_order_no'=>'test0001',
    'amount'=>'1000',
    'pay_type'=>'ALI_QR',
    'client_ip'=>'1.1.1.1',
    'attach'=>'test',
    'notify_url'=>'https://www.google.com',
    );

print(genSign($arrays,"8014d755163742c7a0c26d72a0601e59"));
?>