跳转到主要内容

认证方式

了解如何使用 HMAC-SHA256 签名进行 API 身份验证,确保请求的安全性。

预计阅读 18 分钟编辑此页

认证方式#

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 请求为空字符串) |

签名步骤#

1

获取当前时间戳

获取当前的 Unix 时间戳(秒级精度),转为字符串。

2

构造待签名消息

按顺序拼接:时间戳 + HTTP方法 + 请求路径 + 请求体。

3

计算 HMAC-SHA256

使用 API Secret 作为密钥,对消息进行 HMAC-SHA256 运算。

4

转为十六进制字符串

将签名结果转为小写的十六进制字符串。

代码示例#

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 设置」中切换环境即可创建。

下一步#