API 签名
签名参数
参数名 | 参数说明 | 备注 |
---|---|---|
timestamp | ⼗三位时间戳 | 1699261493465 |
httpMethod | 请求方式 GET/POST | 请求方式须大写 |
requestPath | 请求路径 | 不包含域名 |
bodyString | 请求参数 | GET:为空 POST:请求参数 |
第一步:生成签名字符串
签名字符串固定为:timestamp + httpMethod + requestPath + bodyString
其中 requestPath、bodyString 中的参数,依据参数名使⽤字典顺序排序,去掉空值。
POST 请求
如:创建订单接口
- timestamp:
1699261493465
- httpMethod:
POST
- requestPath:
/open/api/v4/merchant/trade/create
- bodyString:
{
"side": "BUY",
"cryptoCurrency": "USDT",
"address": "0xef17748b259a133a581e236ebc97edce3b50aaaf",
"network": "TRX",
"fiatCurrency": "USD",
"amount": "100",
"depositType": 2,
"payWayCode": "10001",
"alpha2": "US",
"redirectUrl": "",
"callbackUrl": "http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356504"
}bo'dbo'dd
(1)bodyString 参数排序
{"address":"0xef17748b259a133a581e236ebc97edce3b50aaaf","alpha2":"US","amount":"100","callbackUrl":"http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356304","cryptoCurrency":"USDT","depositType":2,"fiatCurrency":"USD","network":"TRX","payWayCode":"10001","side":"BUY"}
(2)拼接签名字符串:
1699261493465POST/open/api/v4/merchant/trade/create{"address":"0xef17748b259a133a581e236ebc97edce3b50aaaf","alpha2":"US","amount":"100","callbackUrl":"http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356304","cryptoCurrency":"USDT","depositType":2,"fiatCurrency":"USD","network":"TRX","payWayCode":"10001","side":"BUY"}
GET 请求
如:查询订单状态接口
- timestamp:1699261493465
- httpMethod:GET
- requestPath:
/open/api/v4/merchant/query/trade?orderNo=1028577684629876736&side=BUY&[email protected]
- bodyString:
(1)requestPath 参数排序
[email protected]&orderNo=1028577684629876736&side=BUY
(2)拼接签名字符串
1699261493465GET/open/api/v4/merchant/query/[email protected]&orderNo=1028577684629876736&side=BUY
第二步:生成您的签名
public class AchSign {
public static String apiSign(String timestamp, String method, String path, Map<String, String> paramMap, String secretkey) throws NoSuchAlgorithmException, InvalidKeyException {
String content = timestamp + method.toUpperCase() + path + getJsonBody(paramMap);
Base64.Encoder base = Base64.getEncoder();
String signVal = base.encodeToString(sha256(content.getBytes(StandardCharsets.UTF_8), secretkey.getBytes(StandardCharsets.UTF_8)));
return signVal;
}
public static byte[] sha256(byte[] message, byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException {
Mac sha256_HMAC = Mac.getInstance("HmacSha256");
SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSha256");
sha256_HMAC.init(secretKey);
return sha256_HMAC.doFinal(message);
}
private static String getJsonBody(Map<String,String> parameters) {
if (parameters == null || parameters.isEmpty()) {
return "";
}
parameters = removeEmptyKeys(parameters);
parameters = (Map) sortObject(parameters);
return JSON.toJSONString(parameters);
}
private static Map removeEmptyKeys(Map map) {
if (map.isEmpty()) {
return map;
}
Map retMap = new HashMap();
Iterator<Map.Entry> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();
if (entry.getValue() != null && !entry.getValue().equals("")) {
retMap.put(entry.getKey(), entry.getValue());
}
}
return retMap;
}
private static Object sortObject(Object obj) {
if (obj instanceof Map) {
return sortMap((Map) obj);
} else if (obj instanceof List) {
sortList((List) obj);
return obj;
}
return null;
}
private static Map sortMap(Map map) {
if (map.isEmpty()) {
return null;
}
SortedMap<String, Object> sortedMap = new TreeMap<>(removeEmptyKeys(map));
for (String sortKey : sortedMap.keySet()) {
if (sortedMap.get(sortKey) instanceof Map) {
sortedMap.put(sortKey, sortMap((Map) sortedMap.get(sortKey)));
} else if (sortedMap.get(sortKey) instanceof List) {
sortedMap.put(sortKey, sortList((List) sortedMap.get(sortKey)));
}
}
return sortedMap;
}
private static List sortList(List list) {
if (list.isEmpty()) {
return null;
}
List objectList = new ArrayList();
List intList = new ArrayList();
List floatList = new ArrayList();
List stringList = new ArrayList();
List jsonArray = new ArrayList();
for (Object obj : list) {
if (obj instanceof Map || obj instanceof List) {
jsonArray.add(obj);
} else if (obj instanceof Integer) {
intList.add(obj);
} else if (obj instanceof BigDecimal) {
floatList.add(obj);
} else if (obj instanceof String) {
stringList.add(obj);
} else {
intList.add(obj);
}
}
Collections.sort(intList);
Collections.sort(floatList);
Collections.sort(stringList);
objectList.addAll(intList);
objectList.addAll(floatList);
objectList.addAll(stringList);
objectList.addAll(jsonArray);
list.clear();
list.addAll(objectList);
List retList = new ArrayList();
for (Object obj : list) {
if (obj instanceof Map) {
retList.add(sortMap((Map) obj));
} else if (obj instanceof List) {
retList.add(sortList((List) obj));
} else {
retList.add(obj);
}
}
return retList;
}
public static void main(String[] args) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis());
String method = "";
String path = "";
Map map = new hashMap();
String secretkey = "";
String sign = apiSign(timestamp, method, path, map, secretkey);
System.out.println(timestamp);
System.out.println(sign);
System.out.println(URLEncoder.encode(sign));
}
}
<?php
function generateSignature($timestamp, $httpMethod, $requestPath,$bodyString, $secretKey) {
// Concatenate parameters for signature string
$signatureString = $timestamp . $httpMethod . $requestPath . $bodyString ;
echo "\n"."signatureString:".$signatureString;
// Generate HMAC SHA256 signature using the secret key
$signature = base64_encode(hash_hmac('sha256', $signatureString, $secretKey, true));
return $signature;
}
//Sort the parameters in lexicographical order and return json String
function getStringToSign($params) {
ksort($params);
$json = json_encode($params);
return stripslashes($json);
}
// Example for On Ramp
$onRampHttpMethod = "POST";
$onRampRequestPath = "/open/api/v4/merchant/trade/create";
$appId= "f83Is2y7L425rxl8";
$onRampSecretKey = "4Yn8RkxDXN71Q3p0";
$timestamp = strval(time() * 1000);
echo "timestamp:".$timestamp;
//request parameters
$paramsToSign = array(
'address' => 'TSx82tWNWe5Ns6t3w94Ye3Gt6E5KeHSoP8',
'alpha2' => 'US',
'amount' => '100',
'callbackUrl' => 'http://payment.jyoumoney.com/alchemyRamp/pay/callback?tradeNo=DZ02207091800356304',
'cryptoCurrency' => 'USDT',
'depositType' => '2',
'network' => 'TRX',
'fiatCurrency' => 'USD',
'payWayCode' => '10001',
'side' => 'BUY',
);
$rawDataToSign = getStringToSign($paramsToSign);
$onRampSignature = generateSignature($timestamp, $onRampHttpMethod, $onRampRequestPath, $rawDataToSign,$onRampSecretKey);
echo "\n"."On Ramp Signature: " . $onRampSignature . PHP_EOL;
?>
import base64
import hashlib
import hmac
import json
from urllib.parse import urlparse, urlencode
def api_sign(timestamp, method, request_url, body, secretkey):
content = timestamp + method.upper() + get_path(request_url) + get_json_body(body)
print(content)
key = secretkey.encode('utf-8')
message = content.encode('utf-8')
signature = hmac.new(key, message, hashlib.sha256).digest()
signature_b64 = base64.b64encode(signature).decode('utf-8')
return signature_b64
def sha256(message, secret):
return hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).digest()
def get_path(request_url):
parsed_url = urlparse(request_url)
path = parsed_url.path
params = dict(parsed_url.query)
if not params:
return path
sorted_params = {k: params[k] for k in sorted(params)}
query_string = urlencode(sorted_params)
return f'{path}?{query_string}'
def get_json_body(body):
try:
json_data = json.loads(body)
except (json.JSONDecodeError, TypeError):
json_data = {}
if not json_data:
return ''
json_data = remove_empty_keys(json_data)
return json.dumps(sort_object(json_data), separators=(',', ':'))
def parse_path(request_url):
parsed_url = urlparse(request_url)
path = parsed_url.path
params = dict(parsed_url.query)
return path, params
def is_json(json_string):
try:
json.loads(json_string)
return True
except (json.JSONDecodeError, TypeError):
return False
def remove_empty_keys(data):
return {k: v for k, v in data.items() if v}
def sort_object(data):
if isinstance(data, dict):
return {k: sort_object(v) for k, v in sorted(data.items())}
elif isinstance(data, list):
data.sort(key=sort_object)
return [sort_object(item) for item in data]
else:
return data
if __name__ == '__main__':
timestamp = ""
request_method = ""
request_url = ""
req_body = {
"XXX": "XXXXX"
}
sign = api_sign(timestamp, method, request_url,get_json_body(json.dumps(req_body)), appSecret)
print(sign)
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"testing"
"time"
)
func PostRequest(url string, headers map[string]string, bodyData map[string]string) ([]byte, error) {
requestBody, err := json.Marshal(bodyData)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return responseBody, nil
}
func APISign(timestamp string, method string, requestURL string, body string, secretKey string) (string, error) {
content := timestamp + strings.ToUpper(method) + getPath(requestURL) + getJSONBody(body)
signature, err := calculateHMACSHA256([]byte(content), []byte(secretKey))
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signature), nil
}
func calculateHMACSHA256(message []byte, secret []byte) ([]byte, error) {
hash := hmac.New(sha256.New, secret)
_, err := hash.Write(message)
if err != nil {
return nil, err
}
return hash.Sum(nil), nil
}
func getPath(requestURL string) string {
u, err := url.Parse(requestURL)
if err != nil {
return ""
}
path := u.Path
query := u.Query()
query.Del("")
keys := make([]string, 0, len(query))
for key := range query {
keys = append(keys, key)
}
sort.Strings(keys)
var encodedParams []string
for _, key := range keys {
encodedParams = append(encodedParams, fmt.Sprintf("%s=%s", key, query.Get(key)))
}
paramsString := strings.Join(encodedParams, "&")
if paramsString != "" {
return path + "?" + paramsString
}
return path
}
func getJSONBody(body string) string {
if body == "" {
return ""
}
var data interface{}
err := json.Unmarshal([]byte(body), &data)
if err != nil {
return ""
}
if dataMap, ok := data.(map[string]interface{}); ok && len(dataMap) == 0 {
return ""
}
removeEmptyKeys(data)
sortedData := sortObject(data)
jsonBytes, err := json.Marshal(sortedData)
if err != nil {
return ""
}
return string(jsonBytes)
}
func removeEmptyKeys(data interface{}) {
switch value := data.(type) {
case map[string]interface{}:
for key, v := range value {
if v == nil || v == "" {
delete(value, key)
} else {
removeEmptyKeys(v)
}
}
case []interface{}:
for _, v := range value {
removeEmptyKeys(v)
}
}
}
func sortObject(data interface{}) interface{} {
switch value := data.(type) {
case map[string]interface{}:
keys := make([]string, 0, len(value))
for k := range value {
keys = append(keys, k)
}
sort.Strings(keys)
sortedMap := make(map[string]interface{})
for _, k := range keys {
v := sortObject(value[k])
sortedMap[k] = v
}
return sortedMap
case []interface{}:
for i, v := range value {
value[i] = sortObject(v)
}
return value
default:
return value
}
}
func main() {
timestamp := fmt.Sprintf("%d", time.Now().UnixNano()/int64(time.Millisecond))
method := "XX"
requestURL := "XXXXX"
req_body := map[string]string{
"XXX": "XXXXX",
}
dataType, _ := json.Marshal(req_body)
dataString := string(dataType)
appId := "XXXXX"
secretKey := "XXXXX"
sign, err := APISign(timestamp, method, requestURL, dataString, secretKey)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
headers := map[string]string{
"appId": appId,
"timestamp": timestamp,
"sign": sign,
}
response, err := PostRequest(requestURL, headers, req_body)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println(string(response))
}
const crypto = require('crypto');
const url = require('url');
function apiSign(timestamp, method, requestUrl, body, secretkey) {
const content = timestamp + method.toUpperCase() + getPath(requestUrl) + getJsonBody(body);
const signVal = crypto.createHmac('sha256', secretkey)
.update(content, 'utf8')
.digest('base64');
return signVal;
}
function sha256(message, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(message);
return hmac.digest();
}
function getPath(requestUrl) {
const uri = new URL(requestUrl);
const path = uri.pathname;
const params = Array.from(uri.searchParams.entries());
if (params.length === 0) {
return path;
} else {
const sortedParams = [...params].sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
const queryString = sortedParams.map(([key, value]) => `${key}=${value}`).join('&');
return `${path}?${queryString}`;
}
}
function getJsonBody(body) {
let map;
try {
map = JSON.parse(body);
} catch (error) {
map = {};
}
if (Object.keys(map).length === 0) {
return '';
}
map = removeEmptyKeys(map);
map = sortObject(map);
return JSON.stringify(map);
}
function parsePath(requestUrl) {
const uri = new URL(requestUrl);
const path = uri.pathname;
const params = Object.fromEntries(uri.searchParams.entries());
return { path, params };
}
function isJson(jsonString) {
if (!jsonString || jsonString === '') {
return false;
}
try {
JSON.parse(jsonString);
return true;
} catch (error) {
return false;
}
}
function removeEmptyKeys(map) {
const retMap = {};
for (const [key, value] of Object.entries(map)) {
if (value !== null && value !== '') {
retMap[key] = value;
}
}
return retMap;
}
function sortObject(obj) {
if (typeof obj === 'object') {
if (Array.isArray(obj)) {
return sortList(obj);
} else {
return sortMap(obj);
}
}
return obj;
}
function sortMap(map) {
const sortedMap = new Map(Object.entries(removeEmptyKeys(map)).sort(([aKey], [bKey]) => aKey.localeCompare(bKey)));
for (const [key, value] of sortedMap.entries()) {
if (typeof value === 'object') {
sortedMap.set(key, sortObject(value));
}
}
return Object.fromEntries(sortedMap.entries());
}
function sortList(list) {
const objectList = [];
const intList = [];
const floatList = [];
const stringList = [];
const jsonArray = [];
for (const item of list) {
if (typeof item === 'object') {
jsonArray.push(item);
} else if (Number.isInteger(item)) {
intList.push(item);
} else if (typeof item === 'number') {
floatList.push(item);
} else if (typeof item === 'string') {
stringList.push(item);
} else {
intList.push(item);
}
}
intList.sort((a, b) => a - b);
floatList.sort((a, b) => a - b);
stringList.sort();
objectList.push(...intList, ...floatList, ...stringList, ...jsonArray);
list.length = 0;
list.push(...objectList);
const retList = [];
for (const item of list) {
if (typeof item === 'object') {
retList.push(sortObject(item));
} else {
retList.push(item);
}
}
return retList;
}
const timestamp = String(Date.now());
const method = 'XXXXX';
const requestUrl = 'XXXXX';
const body = '';
const secretkey = 'XXXXX';
const sign = apiSign(timestamp, method, requestUrl, body, secretkey);
console.log(timestamp);
console.log(sign);
console.log(encodeURIComponent(sign));
Updated about 1 month ago