接口签名
接口签名可以验证请求的合法性,防止请求被篡改或伪造。
签名规则
请求时需携带以下自定义请求头:
请求头字段 | 说明 | 示例值 |
---|---|---|
x-user-id | 用户 ID | 100 |
x-timestamp | 时间戳(秒级) | 1723786112 |
x-nonce | 随机字符串 | 3f8b7c1a92e4d5ff |
x-signature | 生成的签名 | 5e884898da28047151d0e56f8dc62927... |
x-signature
生成规则
- 拼接字符串
请求方法
+ 请求路径
+ 用户ID
+ 秒级时间戳
+ 随机字符串
如:
GET
+/openapi/account
+100
+1723786112
+3f8b7c1a92e4d5ff
- 生成签名
使用 HMAC-SHA256 算法,以 apiKey
作为密钥,对签名字符串进行哈希运算,结果转换为十六进制字符串。
js
const signature = crypto.createHmac('sha256', apiKey)
.update(signString)
.digest('hex')
- 请求接口携带签名请求头
js
fetch('/openapi/account', {
method: 'GET',
headers: {
'x-user-id': '100',
'x-timestamp': '1723786112',
'x-nonce': '3f8b7c1a92e4d5ff',
'x-signature': signature,
},
}).then(res => res.json())
代码示例
Python 示例
python
import time
import hmac
import hashlib
import secrets
import requests
def get_accounts():
method = "GET"
path = "/openapi/account"
userId = "100"
apiKey = "AK-MAD9F4GXPO2PBW0"
timestamp = str(int(time.time()))
nonce = secrets.token_hex(8) # 16位随机十六进制字符串
# 拼接签名字符串
sign_string = method.upper() + path + userId + timestamp + nonce
# 生成签名
signature = hmac.new(apiKey.encode(), sign_string.encode(), hashlib.sha256).hexdigest()
# 发送 GET 请求
url = "https://applo.cc/api" + path # 替换为实际 API 域名
headers = {
"x-user-id": userId,
"x-timestamp": timestamp,
"x-nonce": nonce,
"x-signature": signature,
}
response = requests.get(url, headers=headers)
data = response.json()
return data.get("data")
if __name__ == "__main__":
result = get_accounts()
print(result)
PHP 示例
php
// 获取账号列表
function getAccounts() {
$method = 'GET';
$path = '/openapi/account';
$userId = '100';
$apiKey = 'AK-MAD9F4GXPO2PBW0';
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(8)); // 16位随机十六进制字符串
// 拼接签名字符串
$signString = strtoupper($method) . $path . $userId . $timestamp . $nonce;
// 生成签名
$signature = hash_hmac('sha256', $signString, $apiKey);
// 发起 GET 请求
$url = 'https://applo.cc/api' . $path; // 替换为实际 API 域名
$headers = [
"x-user-id: $userId",
"x-timestamp: $timestamp",
"x-nonce: $nonce",
"x-signature: $signature",
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
return $data['data'] ?? null;
}
// 调用示例
$result = getAccounts();
print_r($result);
Java 示例
java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class ApiClient {
public static String hmacSha256(String key, String data) throws Exception {
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] hash = sha256Hmac.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static String getAccounts() throws Exception {
String method = "GET";
String path = "/openapi/account";
String userId = "100";
String apiKey = "AK-MAD9F4GXPO2PBW0";
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonce = javax.xml.bind.DatatypeConverter.printHexBinary(java.security.SecureRandom.getSeed(8)).toLowerCase();
String signString = method.toUpperCase() + path + userId + timestamp + nonce;
String signature = hmacSha256(apiKey, signString);
String urlStr = "https://applo.cc/api" + path; // 替换为实际 API 域名
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("x-user-id", userId);
conn.setRequestProperty("x-timestamp", timestamp);
conn.setRequestProperty("x-nonce", nonce);
conn.setRequestProperty("x-signature", signature);
Scanner scanner = new Scanner(conn.getInputStream());
StringBuilder response = new StringBuilder();
while (scanner.hasNext()) {
response.append(scanner.nextLine());
}
scanner.close();
return response.toString();
}
public static void main(String[] args) throws Exception {
String result = getAccounts();
System.out.println(result);
}
}
Nodejs 示例
js
const crypto = require('crypto');
// 获取账号列表
const getAccounts = async () => {
const method = 'GET';
const path = `/openapi/account`;
const userId = '100';
const apiKey = 'AK-MAD9F4GXPO2PBW0';
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(8).toString('hex');
const signString = `${method.toUpperCase()}${path}${userId}${timestamp}${nonce}`;
const signature = crypto.createHmac('sha256', apiKey)
.update(signString)
.digest('hex');
const url = 'https://applo.cc/api' + path;
const res = await fetch(url, {
method: 'GET',
headers: {
'x-user-id': userId,
'x-timestamp': timestamp,
'x-nonce': nonce,
'x-signature': signature,
},
}).then(res => res.json())
return res.data;
}
// 调用示例
getAccounts().then(result => {
console.log(result);
});
Go 示例
go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net/http"
"time"
"math/rand"
)
func getAccounts() (string, error) {
method := "GET"
path := "/openapi/account"
userId := "100"
apiKey := "AK-MAD9F4GXPO2PBW0"
timestamp := fmt.Sprintf("%d", time.Now().Unix())
// 生成16位随机十六进制字符串
nonceBytes := make([]byte, 8)
rand.Read(nonceBytes)
nonce := hex.EncodeToString(nonceBytes)
// 拼接签名字符串
signString := method + path + userId + timestamp + nonce
// 生成签名
h := hmac.New(sha256.New, []byte(apiKey))
h.Write([]byte(signString))
signature := hex.EncodeToString(h.Sum(nil))
// 发起 GET 请求
url := "https://applo.cc/api" + path // 替换为实际 API 域名
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("x-user-id", userId)
req.Header.Set("x-timestamp", timestamp)
req.Header.Set("x-nonce", nonce)
req.Header.Set("x-signature", signature)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
return string(body), nil
}
func main() {
result, err := getAccounts()
if err != nil {
panic(err)
}
fmt.Println(result)
}