签名规则
2024年11月10日大约 3 分钟
验签参数
验证接口签名时所需的appkey、appSecret由全渠道提供,具体配置步骤详见准备工作。
步骤
将排序后的参数列表,按照 k1v1k2v2…拼接,结果为
parameters。在
parameters前后拼接上appSecret(appSecret+parameters+appSecret),得到签名原串。将签名原串使用MD5加密为32位大写的字符串,即得到
sign的值。
示例
假如appSecret为88888888,传入参数为:
API
{
"appkey": "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6",
"method": "open.goods.list.get",
"param": "{\"offset\":0,\"size\":1}",
"timestamp": "2024-10-29 10:48:00",
"v": "1.0",
"sign": "8BDC5A4313008AE080EAE170B56B81DE"
}消息
{
"appkey": "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6",
"method": "ORDERSTATUS_UPDATE",
"orderid": "124124124124",
"timestamp": "2024-10-29 10:48:00",
"sign": "A92219783E1A81EA7E18C8D7C3E9FA60"
}MD5加密前的签名原串则为:
API
88888888appkeyA1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6methodopen.goods.list.getparam{"offset":0,"size":1}timestamp2024-10-29 10:48:00v1.088888888
消息
88888888appkeyA1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6methodORDERSTATUS_UPDATEorderid124124124124timestamp2024-10-29 10:48:0088888888
示例代码
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using Newtonsoft.Json;
public class SignatureGenerator
{
public static string GenerateSign(string bodyJsonStr, string appSecret)
{
// 将body里的JSON字符串反序列化为字典
Dictionary<string, string> parameters = JsonConvert.DeserializeObject<Dictionary<string, string>>(bodyJsonStr);
// 移除 sign 参数
parameters.Remove("sign");
// Step 1: 排序参数
var sortedParameters = parameters.OrderBy(kvp => kvp.Key);
// Step 2: 拼接参数
var stringBuilder = new StringBuilder();
foreach (var item in sortedParameters)
{
stringBuilder.Append($"{item.Key}{item.Value}");
}
string parametersString = stringBuilder.ToString();
// Step 3: 拼接 appSecret
string signSource = $"{appSecret}{parametersString}{appSecret}";
// Step 4: MD5 加密
using (MD5 md5 = MD5.Create())
{
byte[] inputBytes = Encoding.UTF8.GetBytes(signSource);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// 将哈希值转换为大写的十六进制字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
}Java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.LinkedHashMap;
import com.google.gson.Gson;
public class SignatureGenerator {
public static String generateSign(String bodyJsonStr, String appSecret) {
// 将JSON字符串反序列化为字典
Map<String, String> parameters = new Gson().fromJson(bodyJsonStr, LinkedHashMap.class);
// 移除 sign 参数
parameters.remove("sign");
// Step 1: 排序参数
Map<String, String> sortedParameters = new TreeMap<>(parameters);
// Step 2: 拼接参数
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParameters.entrySet()) {
stringBuilder.append(entry.getKey()).append(entry.getValue());
}
String parametersString = stringBuilder.toString();
// Step 3: 拼接 appSecret
String signSource = appSecret + parametersString + appSecret;
// Step 4: MD5 加密
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] inputBytes = signSource.getBytes("UTF-8");
byte[] hashBytes = md.digest(inputBytes);
// 将哈希值转换为大写的十六进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException | java.io.UnsupportedEncodingException e) {
throw new RuntimeException("Failed to generate MD5 hash", e);
}
}
}Go
package main
import (
"crypto/md5"
"encoding/json"
"fmt"
"sort"
"strings"
)
type SignatureGenerator struct{}
func (sg *SignatureGenerator) GenerateSign(bodyJsonStr, appSecret string) string {
var parameters map[string]string
// 将JSON字符串反序列化为字典
json.Unmarshal([]byte(bodyJsonStr), ¶meters)
// 移除 sign 参数
delete(parameters, "sign")
// Step 1: 排序参数
keys := make([]string, 0, len(parameters))
for k := range parameters {
keys = append(keys, k)
}
sort.Strings(keys)
// Step 2: 拼接参数
var parametersString strings.Builder
for _, key := range keys {
parametersString.WriteString(key)
parametersString.WriteString(parameters[key])
}
// Step 3: 拼接 appSecret
signSource := appSecret + parametersString.String() + appSecret
// Step 4: MD5 加密
hasher := md5.New()
hasher.Write([]byte(signSource))
hashBytes := hasher.Sum(nil)
// 将哈希值转换为大写的十六进制字符串
return strings.ToUpper(hex.EncodeToString(hashBytes))
}PHP
<?php
class SignatureGenerator
{
public static function generateSign($bodyJsonStr, $appSecret)
{
// 将JSON字符串反序列化为数组
$parameters = json_decode($bodyJsonStr, true);
// 移除 sign 参数
unset($parameters['sign']);
// Step 1: 排序参数
ksort($parameters);
// Step 2: 拼接参数
$parametersString = '';
foreach ($parameters as $key => $value) {
$parametersString .= $key . $value;
}
// Step 3: 拼接 appSecret
$signSource = $appSecret . $parametersString . $appSecret;
// Step 4: MD5 加密
$hashBytes = md5($signSource, true); // 获取原始二进制格式的哈希值
// 将哈希值转换为大写的十六进制字符串
$hexString = bin2hex($hashBytes);
return strtoupper($hexString);
}
}
?>Python
import hashlib
import json
from collections import OrderedDict
class SignatureGenerator:
def generate_sign(self, body_json_str, app_secret):
# 将JSON字符串反序列化为字典
parameters = json.loads(body_json_str)
# 移除 sign 参数
parameters.pop('sign', None)
# Step 1: 排序参数
sorted_parameters = OrderedDict(sorted(parameters.items()))
# Step 2: 拼接参数
parameters_string = ''.join(f'{k}{v}' for k, v in sorted_parameters.items())
# Step 3: 拼接 appSecret
sign_source = f'{app_secret}{parameters_string}{app_secret}'
# Step 4: MD5 加密
hash_bytes = hashlib.md5(sign_source.encode('utf-8')).digest()
# 将哈希值转换为大写的十六进制字符串
hex_string = ''.join(f'{byte:02X}' for byte in hash_bytes)
return hex_string辅助工具
使用签名生成工具排查签名问题。
