签名示例
本文档提供与平台当前规则一致的签名示例。统一规则如下:
- 移除
sign字段 - 过滤值为
null和空字符串的字段 - 按键名 ASCII 升序排序
- 拼接为
key=value&key=value - 使用
HMAC-SHA256计算摘要 - 将摘要结果做
Base64编码
注意:签名内容使用原始参数值,不要额外做 URL 编码。
示例参数
{
"merchantId": "MCH_123456",
"merchantOrderNo": "ORDER_123456",
"amount": "1000000",
"currency": "VND",
"notificationUrl": "https://api.example.com/notify",
"paymentNo": "PAY_123456"
}
拼接后的签名串:
amount=1000000¤cy=VND&merchantId=MCH_123456&merchantOrderNo=ORDER_123456¬ificationUrl=https://api.example.com/notify&paymentNo=PAY_123456
当 signKey = your_secret_key 时,签名结果为:
69kFPVLYmSdqNszSsY5U/L4Rs531x0z2lnQlcRQKUg8=
JavaScript 示例
const crypto = require('crypto');
function buildSignContent(data) {
return Object.entries(data)
.filter(([key, value]) => key !== 'sign' && value !== null && value !== '')
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => `${key}=${String(value)}`)
.join('&');
}
function generateSign(data, signKey) {
const content = buildSignContent(data);
return crypto
.createHmac('sha256', signKey)
.update(content, 'utf8')
.digest('base64');
}
const requestData = {
merchantId: 'MCH_123456',
merchantOrderNo: 'ORDER_123456',
amount: '1000000',
currency: 'VND',
notificationUrl: 'https://api.example.com/notify',
paymentNo: 'PAY_123456',
};
console.log(buildSignContent(requestData));
console.log(generateSign(requestData, 'your_secret_key'));
Python 示例
import base64
import hashlib
import hmac
def build_sign_content(data: dict) -> str:
items = [
(key, str(value))
for key, value in data.items()
if key != "sign" and value is not None and value != ""
]
items.sort(key=lambda item: item[0])
return "&".join(f"{key}={value}" for key, value in items)
def generate_sign(data: dict, sign_key: str) -> str:
content = build_sign_content(data)
digest = hmac.new(
sign_key.encode("utf-8"),
content.encode("utf-8"),
hashlib.sha256,
).digest()
return base64.b64encode(digest).decode("utf-8")
request_data = {
"merchantId": "MCH_123456",
"merchantOrderNo": "ORDER_123456",
"amount": "1000000",
"currency": "VND",
"notificationUrl": "https://api.example.com/notify",
"paymentNo": "PAY_123456",
}
print(build_sign_content(request_data))
print(generate_sign(request_data, "your_secret_key"))
Java 示例
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class SignatureExample {
public static String buildSignContent(Map<String, Object> data) {
Map<String, String> filtered = new TreeMap<>();
for (Map.Entry<String, Object> entry : data.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (!"sign".equals(key) && value != null && !"".equals(value)) {
filtered.put(key, String.valueOf(value));
}
}
return filtered.entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
}
public static String generateSign(Map<String, Object> data, String signKey) throws Exception {
String content = buildSignContent(data);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] digest = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(digest);
}
}
PHP 示例
<?php
function buildSignContent(array $data): string
{
unset($data['sign']);
$filtered = array_filter(
$data,
fn ($value) => $value !== null && $value !== ''
);
ksort($filtered, SORT_STRING);
return implode('&', array_map(
fn ($key, $value) => $key . '=' . strval($value),
array_keys($filtered),
array_values($filtered)
));
}
function generateSign(array $data, string $signKey): string
{
$content = buildSignContent($data);
$digest = hash_hmac('sha256', $content, $signKey, true);
return base64_encode($digest);
}
$requestData = [
'merchantId' => 'MCH_123456',
'merchantOrderNo' => 'ORDER_123456',
'amount' => '1000000',
'currency' => 'VND',
'notificationUrl' => 'https://api.example.com/notify',
'paymentNo' => 'PAY_123456',
];
echo buildSignContent($requestData) . PHP_EOL;
echo generateSign($requestData, 'your_secret_key') . PHP_EOL;
Go 示例
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"sort"
"strings"
)
func buildSignContent(data map[string]string) string {
delete(data, "sign")
keys := make([]string, 0, len(data))
for key, value := range data {
if value != "" {
keys = append(keys, key)
}
}
sort.Strings(keys)
parts := make([]string, 0, len(keys))
for _, key := range keys {
parts = append(parts, key+"="+data[key])
}
return strings.Join(parts, "&")
}
func generateSign(data map[string]string, signKey string) string {
content := buildSignContent(data)
mac := hmac.New(sha256.New, []byte(signKey))
mac.Write([]byte(content))
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
func main() {
requestData := map[string]string{
"merchantId": "MCH_123456",
"merchantOrderNo": "ORDER_123456",
"amount": "1000000",
"currency": "VND",
"notificationUrl": "https://api.example.com/notify",
"paymentNo": "PAY_123456",
}
fmt.Println(buildSignContent(requestData))
fmt.Println(generateSign(requestData, "your_secret_key"))
}