签名算法
算法描述
参与签名的字段分别是:
apiPath:URI(必须)body:请求体(必须),JSON字符串x-api-key:同appId(必须)x-api-timestamp:当前时间戳,单位毫秒(必须)- 其他在URI中的参数
按照以下步骤实现:
- 将以上所有参数的名称和值放入
contentMap,对contentMap的key进行升序排序 - 对
contentMap进行JSON序列化 - 使用
SHA256算法对JSON字符串+密钥进行加密 - 最后对加密结果进行
BASE64编码,得到的结果就是签名字符串
如以下示例:
shell
curl -H 'x-api-key: key' \
-H 'x-api-timestamp: 1744636844000' \
-H 'x-api-signature: 0xb7Kxxxx=' \
'https://{HOST}/path/to/pay?param1=test1¶m2=test2' \
-d '{"data":"test"}'
curl -H 'x-api-key: key' \
-H 'x-api-timestamp: 1744636844000' \
-H 'x-api-signature: 0xb7Kxxxx=' \
'https://{HOST}/path/to/pay?param1=test1¶m2=test2' \
-d '{"data":"test"}'JSON序列化后的contentMap如下:
json
{
"apiPath": "/path/to/pay",
"body": {
"data": "test"
},
"param1": "test1",
"param2": "test2",
"x-api-key": "key",
"x-api-timestamp": "17200001"
}{
"apiPath": "/path/to/pay",
"body": {
"data": "test"
},
"param1": "test1",
"param2": "test2",
"x-api-key": "key",
"x-api-timestamp": "17200001"
}最后对这个JSON字符串进行加密。
代码实现
后端实现示例
go
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"sort"
)
func GenSign(appId, apiSecret, pathUrl, payload string, tm int64) string {
// 解析 URL
path := ""
contentMap := make(map[string]string)
if u, err := url.Parse(pathUrl); err == nil {
path = u.Path
for k, v := range u.Query() {
if len(v) > 0 {
contentMap[k] = v[0]
}
}
}
// 构建待签名的 map
contentMap["x-api-key"] = appId
contentMap["x-api-timestamp"] = fmt.Sprintf("%d", tm) // 毫秒
contentMap["apiPath"] = path
contentMap["body"] = payload
// 获取所有 keys 并排序
keys := make([]string, 0, len(contentMap))
for k := range contentMap {
keys = append(keys, k)
}
sort.Strings(keys)
// 创建有序的 map
orderedMap := make(map[string]string)
for _, k := range keys {
orderedMap[k] = contentMap[k]
}
// JSON 序列化
content, _ := json.Marshal(orderedMap)
// 计算 HMAC
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write(content)
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
// 使用示例
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1¶m2=test2", `{"data":"test"}`, time.Now().UnixMilli())
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"sort"
)
func GenSign(appId, apiSecret, pathUrl, payload string, tm int64) string {
// 解析 URL
path := ""
contentMap := make(map[string]string)
if u, err := url.Parse(pathUrl); err == nil {
path = u.Path
for k, v := range u.Query() {
if len(v) > 0 {
contentMap[k] = v[0]
}
}
}
// 构建待签名的 map
contentMap["x-api-key"] = appId
contentMap["x-api-timestamp"] = fmt.Sprintf("%d", tm) // 毫秒
contentMap["apiPath"] = path
contentMap["body"] = payload
// 获取所有 keys 并排序
keys := make([]string, 0, len(contentMap))
for k := range contentMap {
keys = append(keys, k)
}
sort.Strings(keys)
// 创建有序的 map
orderedMap := make(map[string]string)
for _, k := range keys {
orderedMap[k] = contentMap[k]
}
// JSON 序列化
content, _ := json.Marshal(orderedMap)
// 计算 HMAC
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write(content)
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
// 使用示例
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1¶m2=test2", `{"data":"test"}`, time.Now().UnixMilli())php
<?php
function GenSign(
string $appId,
string $apiSecret,
string $pathUrl,
string $payload,
int $tm): string {
$contentMap = [];
$parts = parse_url($pathUrl);
$path = $parts['path'] ?? '';
if (!empty($parts['query'])) {
parse_str($parts['query'], $queryArr);
foreach ($queryArr as $k => $v) {
$contentMap[$k] = (string)$v;
}
}
$contentMap['x-api-key'] = $appId;
$contentMap['x-api-timestamp'] = (string)$tm;
$contentMap['apiPath'] = $path;
$contentMap['body'] = $payload;
ksort($contentMap, SORT_STRING);
$json = json_encode(
$contentMap,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
$raw = hash_hmac('sha256', $json, $apiSecret, true);
return base64_encode($raw);
}
// 使用示例
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1¶m2=test2", '{"data":"test"}', floor(microtime(true) * 1000))<?php
function GenSign(
string $appId,
string $apiSecret,
string $pathUrl,
string $payload,
int $tm): string {
$contentMap = [];
$parts = parse_url($pathUrl);
$path = $parts['path'] ?? '';
if (!empty($parts['query'])) {
parse_str($parts['query'], $queryArr);
foreach ($queryArr as $k => $v) {
$contentMap[$k] = (string)$v;
}
}
$contentMap['x-api-key'] = $appId;
$contentMap['x-api-timestamp'] = (string)$tm;
$contentMap['apiPath'] = $path;
$contentMap['body'] = $payload;
ksort($contentMap, SORT_STRING);
$json = json_encode(
$contentMap,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
$raw = hash_hmac('sha256', $json, $apiSecret, true);
return base64_encode($raw);
}
// 使用示例
GenSign("A123456", "ABC123", "/path/to/pay?param1=test1¶m2=test2", '{"data":"test"}', floor(microtime(true) * 1000))Postman Pre-request Script
用于在Postman中自动生成签名,将以下脚本粘贴到Pre-request Script标签页:
javascript
const appId = 'YOUR_APP_ID';
const apiSecret = 'YOUR_API_SECRET';
const ts = Date.now();
pm.request.headers.upsert({ key: 'x-api-key', value: appId });
pm.request.headers.upsert({ key: 'x-api-timestamp', value: String(ts) });
const path = pm.request.url.getPath();
const rawBody =
pm.request.body && pm.request.body.raw ? pm.request.body.raw : '';
const bodyForSign = rawBody.replace(/\r?\n/g, '');
const ordered = {
apiPath: path,
body: bodyForSign,
'x-api-key': appId,
'x-api-timestamp': String(ts),
};
const content = JSON.stringify(ordered);
console.log('Signature content:', ordered);
const signature = CryptoJS.HmacSHA256(content, apiSecret).toString(
CryptoJS.enc.Base64
);
pm.request.headers.upsert({ key: 'x-api-signature', value: signature });
console.log('Generated signature:', signature);const appId = 'YOUR_APP_ID';
const apiSecret = 'YOUR_API_SECRET';
const ts = Date.now();
pm.request.headers.upsert({ key: 'x-api-key', value: appId });
pm.request.headers.upsert({ key: 'x-api-timestamp', value: String(ts) });
const path = pm.request.url.getPath();
const rawBody =
pm.request.body && pm.request.body.raw ? pm.request.body.raw : '';
const bodyForSign = rawBody.replace(/\r?\n/g, '');
const ordered = {
apiPath: path,
body: bodyForSign,
'x-api-key': appId,
'x-api-timestamp': String(ts),
};
const content = JSON.stringify(ordered);
console.log('Signature content:', ordered);
const signature = CryptoJS.HmacSHA256(content, apiSecret).toString(
CryptoJS.enc.Base64
);
pm.request.headers.upsert({ key: 'x-api-signature', value: signature });
console.log('Generated signature:', signature);