💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### 数字签名 (1)为了保证数据传输过程中的数据真实性和完整性,我们需要对数据进行数字签名,在接收签名数据之后进行签名校验。 (2)签名有两个步骤,先按一定规则拼接要签名的原始串,再选择具体的算法和密钥计算出签名结果。 (3)原始串中,字段名和字段值都采用原始值,不进行URL Encode。 (4)平台返回的应答或通知消息可能会由于升级增加参数,请验证应答签名时注意允许这种情况。 ### 签名方法 (1)设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1\&key2=value2…)拼接成字符串stringA。 (2)在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。 ### 签名样例 (1)假设需要传递的参数如下 ``` array:12 [▼ "order_id" => "PT2307041351078661" "oil_type" => "92#" "oil_gun" => "1号枪" "oil_price" => "6.25" "oil_volume" => "56" "order_total" => "350" "order_time" => "2023-07-04 13:51:07" "card_no" => "" "appid" => "230703147355731" "station_number" => "OP12335566" "brand" => "zx001" "nonce_str" => "64a3b34bda295" ] ``` (2)对参数按照key=value的格式,并按照参数名ASCII字典序排序如下 ``` appid=230703147355731&brand=zx001&nonce_str=64a3b34bda295&oil_gun=1号枪&oil_price=6.25&oil_type=92#&oil_volume=56&order_id=PT2307041351078661&order_time=2023-07-04 13:51:07&order_total=350&station_number=OP12335566 ``` (3)拼接秘钥key (同AppSecret) ``` appid=230703147355731&brand=zx001&nonce_str=64a3b34bda295&oil_gun=1号枪&oil_price=6.25&oil_type=92#&oil_volume=56&order_id=PT2307041351078661&order_time=2023-07-04 13:51:07&order_total=350&station_number=OP12335566&key=019fa2de62ee14771ea8b76820e8dc18 ``` 4)计算签名 ``` 签名结果: 58DF44E3766423064265B0332D45BE19 MD5计算:sign=MD5(stringSignTemp).toUpperCase() ``` **注:md5加密为32位 且 大写。除sign字段外,其他参数按照签名方法验签,空值不传递,不参与签名组串。** ***** ## 签名方法demo: PHP: ```php function calculateSign($data, $key) { // 去除空值参数和sign字段 $filteredData = array_filter($data, function($value, $key) { return $value !== '' && strtolower($key) !== 'sign'; }, ARRAY_FILTER_USE_BOTH); // 将参数按照参数名ASCII码从小到大排序 ksort($filteredData); // 使用URL键值对的格式拼接参数 $stringA = ''; foreach ($filteredData as $k => $v) { $stringA .= $k . '=' . $v . '&'; } $stringA .= 'key=' . $key; // 对拼接后的字符串进行MD5运算,并转换为大写 $signValue = strtoupper(md5($stringA)); return $signValue; } ``` Java: ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class SignCalculator { public static String calculateSign(Map<String, String> data, String key) throws NoSuchAlgorithmException { // 去除空值参数和sign字段 Map<String, String> filteredData = new HashMap<>(); for (Map.Entry<String, String> entry : data.entrySet()) { if (!entry.getValue().isEmpty() && !entry.getKey().equalsIgnoreCase("sign")) { filteredData.put(entry.getKey(), entry.getValue()); } } // 将参数按照参数名ASCII码从小到大排序 List<String> sortedKeys = new ArrayList<>(filteredData.keySet()); Collections.sort(sortedKeys); // 使用URL键值对的格式拼接参数 StringBuilder stringA = new StringBuilder(); for (String k : sortedKeys) { stringA.append(k).append("=").append(filteredData.get(k)).append("&"); } stringA.append("key=").append(key); // 对拼接后的字符串进行MD5运算,并转换为大写 MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] digest = md5.digest(stringA.toString().getBytes()); StringBuilder signValue = new StringBuilder(); for (byte b : digest) { signValue.append(String.format("%02x", b & 0xff)); } return signValue.toString().toUpperCase(); } public static void main(String[] args) throws NoSuchAlgorithmException { // 示例用法 Map<String, String> data = new HashMap<>(); data.put("sign", "xxxxxx"); data.put("key1", "value1"); data.put("key2", ""); data.put("", "value3"); String key = "your_key"; String signValue = calculateSign(data, key); System.out.println(signValue); } } ``` C# ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; public class SignCalculator { public static string CalculateSign(Dictionary<string, string> data, string key) { // 去除空值参数和sign字段 var filteredData = data.Where(x => !string.IsNullOrEmpty(x.Value) && x.Key.ToLower() != "sign") .ToDictionary(x => x.Key, x => x.Value); // 将参数按照参数名ASCII码从小到大排序 var sortedData = filteredData.OrderBy(x => x.Key); // 使用URL键值对格式拼接参数 StringBuilder stringA = new StringBuilder(); foreach (var pair in sortedData) { stringA.Append(pair.Key).Append("=").Append(pair.Value).Append("&"); } stringA.Append("key=").Append(key); // 对拼接后的字符串进行MD5运算,并转换为大写 using (var md5 = MD5.Create()) { byte[] bytes = Encoding.UTF8.GetBytes(stringA.ToString()); byte[] hashBytes = md5.ComputeHash(bytes); var signValue = new StringBuilder(); foreach (byte b in hashBytes) { signValue.Append(b.ToString("x2")); } return signValue.ToString().ToUpper(); } } public static void Main(string[] args) { // 示例用法 Dictionary<string, string> data = new Dictionary<string, string> { { "sign", "xxxxxx" }, { "key1", "value1" }, { "key2", "" }, { "", "value3" } }; string key = "your_key"; string signValue = CalculateSign(data, key); Console.WriteLine(signValue); } } ``` Python: ```python import hashlib from typing import Dict def calculate_sign(data: Dict[str, str], key: str) -> str: # 去除空值参数和sign字段 filtered_data = {k: v for k, v in data.items() if v and k.lower() != "sign"} # 将参数按照参数名ASCII码从小到大排序 sorted_keys = sorted(filtered_data.keys()) # 使用URL键值对的格式拼接参数 string_a = "&".join(f"{k}={filtered_data[k]}" for k in sorted_keys) string_a += f"&key={key}" # 对拼接后的字符串进行MD5运算,并转换为大写 sign_value = hashlib.md5(string_a.encode("utf-8")).hexdigest().upper() return sign_value # 示例用法 data = { "sign": "xxxxxx", "key1": "value1", "key2": "", "": "value3" } key = "your_key" sign_value = calculate_sign(data, key) print(sign_value) ``` Golang: ```go package main import ( "crypto/md5" "encoding/hex" "sort" "strings" ) func calculateSign(data map[string]string, key string) string { // 去除空值参数和sign字段 filteredData := make(map[string]string) for k, v := range data { if v != "" && strings.ToLower(k) != "sign" { filteredData[k] = v } } // 将参数按照参数名ASCII码从小到大排序 var sortedKeys []string for k := range filteredData { sortedKeys = append(sortedKeys, k) } sort.Strings(sortedKeys) // 使用URL键值对的格式拼接参数 var stringA string for _, k := range sortedKeys { stringA += k + "=" + filteredData[k] + "&" } stringA += "key=" + key // 对拼接后的字符串进行MD5运算,并转换为大写 hash := md5.Sum([]byte(stringA)) signValue := hex.EncodeToString(hash[:]) return strings.ToUpper(signValue) } func main() { // 示例用法 data := map[string]string{ "sign": "xxxxxx", "key1": "value1", "key2": "", "": "value3", } key := "your_key" signValue := calculateSign(data, key) println(signValue) } ``` C++: ```cpp #include <iostream> #include <map> #include <algorithm> #include <cctype> #include <iomanip> #include <sstream> #include <openssl/md5.h> std::string calculateSign(const std::map<std::string, std::string>& data, const std::string& key) { // 去除空值参数和sign字段 std::map<std::string, std::string> filteredData; for (const auto& pair : data) { if (!pair.second.empty() && pair.first != "sign") { filteredData[pair.first] = pair.second; } } // 将参数按照参数名ASCII码从小到大排序 std::vector<std::string> sortedKeys; for (const auto& pair : filteredData) { sortedKeys.push_back(pair.first); } std::sort(sortedKeys.begin(), sortedKeys.end()); // 使用URL键值对的格式拼接参数 std::stringstream stringAStream; for (const auto& key : sortedKeys) { stringAStream << key << "=" << filteredData[key] << "&"; } stringAStream << "key=" << key; std::string stringA = stringAStream.str(); // 对拼接后的字符串进行MD5运算,并转换为大写 unsigned char hash[MD5_DIGEST_LENGTH]; MD5(reinterpret_cast<const unsigned char*>(stringA.c_str()), stringA.size(), hash); std::stringstream signValueStream; signValueStream << std::hex << std::uppercase << std::setfill('0'); for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { signValueStream << std::setw(2) << static_cast<unsigned>(hash[i]); } std::string signValue = signValueStream.str(); return signValue; ``` JavaScript: ``` function calculateSign(data, key) { // 去除空值参数和sign字段 const filteredData = {}; for (const [k, v] of Object.entries(data)) { if (v && k.toLowerCase() !== 'sign') { filteredData[k] = v; } } // 将参数按照参数名ASCII码从小到大排序 const sortedKeys = Object.keys(filteredData).sort(); // 使用URL键值对的格式拼接参数 let stringA = sortedKeys.map(k => `${k}=${filteredData[k]}`).join('&'); stringA += `&key=${key}`; // 对拼接后的字符串进行MD5运算,并转换为大写 const md5 = require('crypto').createHash('md5'); const signValue = md5.update(stringA).digest('hex').toUpperCase(); return signValue; } // 示例用法 const data = { sign: 'xxxxxx', key1: 'value1', key2: '', '': 'value3', }; const key = 'your_key'; const signValue = calculateSign(data, key); console.log(signValue); ```