认证方式
了解如何使用 HMAC-SHA256 签名进行 API 身份验证,确保请求的安全性。
认证方式#
eBay AI 广告平台 Open API 使用 HMAC-SHA256 签名进行身份验证。所有 API 请求都必须包含有效的签名,以确保请求的真实性和完整性。
认证概述#
每个 API 请求需要在 HTTP Header 中包含以下认证信息:
| Header | 说明 | 示例 |
|--------|------|------|
| X-API-Key | 您的 API Key | ak_1234567890abcdef |
| X-Signature | HMAC-SHA256 签名 | a1b2c3d4e5... |
| X-Timestamp | Unix 时间戳(秒) | 1704873600 |
签名算法#
签名公式#
signature = HMAC-SHA256(api_secret, message)
message = timestamp + method + path + body
参数说明#
| 参数 | 类型 | 说明 |
|------|------|------|
| api_secret | string | 您的 API Secret(作为 HMAC 密钥) |
| timestamp | string | 当前 Unix 时间戳(秒),如 "1704873600" |
| method | string | HTTP 方法大写,如 "GET"、"POST" |
| path | string | 请求路径(不含域名和查询参数),如 "/campaigns" |
| body | string | 请求体 JSON 字符串(GET 请求为空字符串) |
签名步骤#
获取当前时间戳
获取当前的 Unix 时间戳(秒级精度),转为字符串。
构造待签名消息
按顺序拼接:时间戳 + HTTP方法 + 请求路径 + 请求体。
计算 HMAC-SHA256
使用 API Secret 作为密钥,对消息进行 HMAC-SHA256 运算。
转为十六进制字符串
将签名结果转为小写的十六进制字符串。
代码示例#
Python#
import hmac
import hashlib
import time
def generate_signature(
api_secret: str,
method: str,
path: str,
body: str = ""
) -> tuple[str, str]:
"""
生成 API 请求签名
Args:
api_secret: API Secret
method: HTTP 方法 (GET, POST, PUT, DELETE)
path: 请求路径 (如 /campaigns)
body: 请求体 JSON 字符串
Returns:
(signature, timestamp) 元组
"""
# 步骤 1: 获取时间戳
timestamp = str(int(time.time()))
# 步骤 2: 构造待签名消息
message = f"{timestamp}{method.upper()}{path}{body}"
# 步骤 3 & 4: 计算 HMAC-SHA256 并转为十六进制
signature = hmac.new(
api_secret.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature, timestamp
# 使用示例
API_SECRET = "sk_abcdef1234567890abcdef1234567890"
# GET 请求(无请求体)
sig, ts = generate_signature(API_SECRET, "GET", "/campaigns")
print(f"Signature: {sig}")
print(f"Timestamp: {ts}")
# POST 请求(有请求体)
body = '{"name":"新活动","budget_daily":100}'
sig, ts = generate_signature(API_SECRET, "POST", "/campaigns", body)
print(f"Signature: {sig}")
Node.js#
const crypto = require('crypto');
/**
* 生成 API 请求签名
* @param {string} apiSecret - API Secret
* @param {string} method - HTTP 方法
* @param {string} path - 请求路径
* @param {string} body - 请求体 JSON 字符串
* @returns {{ signature: string, timestamp: string }}
*/
function generateSignature(apiSecret, method, path, body = '') {
// 步骤 1: 获取时间戳
const timestamp = Math.floor(Date.now() / 1000).toString();
// 步骤 2: 构造待签名消息
const message = `${timestamp}${method.toUpperCase()}${path}${body}`;
// 步骤 3 & 4: 计算 HMAC-SHA256 并转为十六进制
const signature = crypto
.createHmac('sha256', apiSecret)
.update(message)
.digest('hex');
return { signature, timestamp };
}
// 使用示例
const API_SECRET = 'sk_abcdef1234567890abcdef1234567890';
// GET 请求
const { signature, timestamp } = generateSignature(
API_SECRET,
'GET',
'/campaigns'
);
console.log(`Signature: ${signature}`);
console.log(`Timestamp: ${timestamp}`);
Java#
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
public class ApiAuth {
public static String[] generateSignature(
String apiSecret,
String method,
String path,
String body
) throws Exception {
// 步骤 1: 获取时间戳
String timestamp = String.valueOf(Instant.now().getEpochSecond());
// 步骤 2: 构造待签名消息
String message = timestamp + method.toUpperCase() + path + (body != null ? body : "");
// 步骤 3: 计算 HMAC-SHA256
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
apiSecret.getBytes(StandardCharsets.UTF_8),
"HmacSHA256"
);
hmac.init(secretKey);
byte[] hash = hmac.doFinal(message.getBytes(StandardCharsets.UTF_8));
// 步骤 4: 转为十六进制
StringBuilder signature = new StringBuilder();
for (byte b : hash) {
signature.append(String.format("%02x", b));
}
return new String[] { signature.toString(), timestamp };
}
public static void main(String[] args) throws Exception {
String apiSecret = "sk_abcdef1234567890abcdef1234567890";
String[] result = generateSignature(apiSecret, "GET", "/campaigns", "");
System.out.println("Signature: " + result[0]);
System.out.println("Timestamp: " + result[1]);
}
}
cURL / Bash#
#!/bin/bash
API_SECRET="sk_abcdef1234567890abcdef1234567890"
METHOD="GET"
PATH="/campaigns"
BODY=""
# 步骤 1: 获取时间戳
TIMESTAMP=$(date +%s)
# 步骤 2: 构造待签名消息
MESSAGE="${TIMESTAMP}${METHOD}${PATH}${BODY}"
# 步骤 3 & 4: 计算 HMAC-SHA256
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$API_SECRET" | awk '{print $2}')
echo "Signature: $SIGNATURE"
echo "Timestamp: $TIMESTAMP"
完整请求示例#
GET 请求#
GET /api/v1/open/campaigns HTTP/1.1
Host: api.eaby-ads.com
Content-Type: application/json
X-API-Key: ak_1234567890abcdef
X-Signature: a1b2c3d4e5f6789012345678901234567890abcd1234567890abcdef12345678
X-Timestamp: 1704873600
POST 请求#
POST /api/v1/open/campaigns HTTP/1.1
Host: api.eaby-ads.com
Content-Type: application/json
X-API-Key: ak_1234567890abcdef
X-Signature: b2c3d4e5f6a1789012345678901234567890abcd1234567890abcdef12345678
X-Timestamp: 1704873600
{
"name": "新年促销活动",
"ebay_account_id": 123,
"budget_daily": 100.00
}
签名验证规则#
服务端会对每个请求进行以下验证:
1. 时间戳有效性#
时间戳必须在当前服务器时间的 ±5 分钟 范围内,否则返回 TIMESTAMP_EXPIRED 错误。
{
"success": false,
"error": {
"code": "TIMESTAMP_EXPIRED",
"message": "请求时间戳已过期,请检查服务器时间是否准确"
}
}
解决方案:
- 确保您的服务器时间已同步(使用 NTP)
- 检查时区设置,时间戳应为 UTC 时间
2. 签名匹配#
服务端会使用相同的算法重新计算签名,并与请求中的签名进行比对。
{
"success": false,
"error": {
"code": "INVALID_SIGNATURE",
"message": "请求签名验证失败"
}
}
常见原因及解决方案:
| 原因 | 解决方案 | |------|----------| | API Secret 错误 | 检查 Secret 是否完整、无多余空格 | | 消息拼接顺序错误 | 确保顺序为:timestamp + method + path + body | | HTTP 方法大小写 | 确保方法为大写(GET, POST 等) | | 请求体不一致 | 确保签名时使用的 body 与实际发送的完全一致 | | 字符编码问题 | 确保使用 UTF-8 编码 |
3. API Key 有效性#
验证 API Key 是否存在且未被禁用。
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "API Key 无效或已被禁用"
}
}
安全最佳实践#
请务必遵循以下安全建议,保护您的 API 凭证:
凭证保护#
- ❌ 不要 在客户端代码(前端、移动 App)中存储 API Secret
- ❌ 不要 将凭证提交到代码仓库
- ❌ 不要 在日志中输出完整的 API Secret
- ✅ 使用环境变量存储敏感信息
- ✅ 使用密钥管理服务(如 AWS Secrets Manager、HashiCorp Vault)
- ✅ 定期轮换 API 凭证
传输安全#
- ✅ 始终使用 HTTPS 协议
- ✅ 验证 SSL/TLS 证书
- ✅ 使用 TLS 1.2 或更高版本
请求安全#
- ✅ 实现请求重试时的指数退避
- ✅ 在服务端保留请求日志用于审计
- ✅ 监控异常的 API 调用模式
调试工具#
在线签名验证器#
我们提供了在线工具帮助您验证签名计算是否正确:
测试环境#
建议在开发阶段使用沙箱环境:
| 环境 | 基础 URL |
|------|----------|
| 生产环境 | https://api.eaby-ads.com/api/v1/open |
| 沙箱环境 | https://sandbox.eaby-ads.com/api/v1/open |
沙箱环境使用独立的 API 凭证,在控制台的「API 设置」中切换环境即可创建。