API 認證授權
概述
Taker API 使用 API Key + Secret 簽名認證方式。開發者必須使用其 API Key 和 API Secret 對每個請求進行簽名。簽名是透過將請求方法、請求路徑、時間戳記與請求參數/主體以 | 符號串接,然後應用 HMAC-SHA256 雜湊演算法生成的。簽名與相關元資料會包含在請求標頭中。伺服器會驗證簽名、驗證使用者身份,並授權後才處理請求。
認證流程
每個請求必須包含:
- API Key
- 時間戳記
- 使用 API Secret 與請求內容計算的簽名
API 會驗證:
- API Key 是否有效且啟用中
- 簽名是否與請求內容匹配
- 時間戳記是否在允許的範圍內(預設誤差 ±5 分鐘)
若以上任一項驗證失敗,請求將返回錯誤碼,如:
json
{"code":10010008,"message":"Signature verification failed"}必填請求標頭
所有經過身份驗證的 API 請求必須包含下列自訂標頭:
| 標頭名稱 | 範例值 | 說明 |
|---|---|---|
X-API-Key | A1B2C3D4E5F6... | 您的公用 API 金鑰 |
X-API-Signature | a8f9c3e... | 經 HMAC-SHA256 產生的簽名 |
X-API-Timestamp | 1715100000000 | 當前的 UNIX 毫秒級時間戳 |
選填(建議用於追蹤):
| 標頭名稱 | 範例值 | 說明 |
|---|---|---|
X-REQUEST-ID | uuid-string | 用戶端自定請求 ID,便於除錯與日誌關聯追蹤 |
簽名生成步驟
使用 大寫 的 HTTP 請求方法(例如:
POST)。接著使用
|連接 API 路徑(不含網域與協議,必須以/開頭!如/api/v1/orders)。再接上 UNIX 毫秒級時間戳。
最後接上請求參數:
- GET 請求:使用
key=value串連的查詢參數(不含?),若無則為空字串。注意,請求的參數不要改變其順序,要確保簽署的和請求的參數是一致的。 - 非 GET 請求:使用原始 JSON 字串作為 body,若無則為空字串。注意,請確保請求體和簽名的一致,不要因為類似格式化而改變,導致請求的和簽名的不是同一份正文。
- GET 請求:使用
最終簽名字串格式:
{request_method}|{request_path}|{timestamp}|{query_string_or_request_body}使用 API Secret 對此簽名字串進行 HMAC-SHA256 加密。
將結果進行 Base64 編碼。
將下列標頭加入請求:
X-API-KeyX-API-TimestampX-API-Signature
範例(簽名字串構造流程):
POST|/api/v1/orders/lock|1746774142003|{"order_hash":"0x1234..."}最終簽名為:
Base64(HMAC-SHA256(signature_string, API_Secret))代碼示例
python
import requests
import hmac
import hashlib
import base64
import time
class TakerApiClient:
def __init__(self, api_key, api_secret, base_url):
self.api_key = api_key
self.api_secret = api_secret
self.base_url = base_url
def send_request(self, method, path, query_string='', body=''):
timestamp = int(time.time() * 1000) # 毫秒
signature_string = self.build_signature_string(method, path, timestamp, query_string, body)
signature = self.generate_signature(signature_string, self.api_secret)
url = self.base_url + path
if query_string:
url += '?' + query_string
headers = {
'X-API-Key': self.api_key,
'X-API-Timestamp': str(timestamp),
'X-API-Signature': signature,
'Content-Type': 'application/json'
}
if method.upper() == 'GET':
response = requests.get(url, headers=headers)
else:
response = requests.request(method.upper(), url, headers=headers, data=body)
return response.text
def build_signature_string(self, method, path, timestamp, query_string, body):
signature_string = f"{method.upper()}|{path}|{timestamp}"
if method.upper() == 'GET':
signature_string += f"|{query_string}"
else:
signature_string += f"|{body}"
return signature_string
def generate_signature(self, data, secret):
key = secret.encode('utf-8')
message = data.encode('utf-8')
hmac_obj = hmac.new(key, message, hashlib.sha256)
return base64.b64encode(hmac_obj.digest()).decode('utf-8')
# 使用示例
api_key = 'your_api_key_here'
api_secret = 'your_api_secret_here'
base_url = '{API_BASE_URL}'
client = TakerApiClient(api_key, api_secret, base_url)
# 鎖定訂單示例
lock_body = '{"order_hash":"0x1234...","lock_duration":300}'
response = client.send_request('POST', '/api/v1/orders/lock', body=lock_body)
print('鎖定響應:', response)
# 查詢訂單示例
query_response = client.send_request('GET', '/api/v1/orders', 'status=locked&page=1&page_size=20')
print('查詢響應:', query_response)常見使用場景
鎖定訂單
bash
curl -X POST "{API_BASE_URL}/api/v1/orders/lock" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-API-Timestamp: 1715100000000" \
-H "X-API-Signature: GENERATED_SIGNATURE" \
-H "Content-Type: application/json" \
-d '{"order_hash":"0x1234...","lock_duration":300}'成交訂單
bash
curl -X POST "{API_BASE_URL}/api/v1/orders/fill" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-API-Timestamp: 1715100000000" \
-H "X-API-Signature: GENERATED_SIGNATURE" \
-H "Content-Type: application/json" \
-d '{"order_hash":"0x1234...","fill_quantity":"100"}'查詢訂單
bash
curl -X GET "{API_BASE_URL}/api/v1/orders?status=locked&page=1&page_size=20" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-API-Timestamp: 1715100000000" \
-H "X-API-Signature: GENERATED_SIGNATURE"錯誤碼
| 代碼 | 消息 | 說明 | 解決方案 |
|---|---|---|---|
| 10010008 | Signature verification failed | 簽名不匹配 | 檢查簽名生成邏輯,確保參數一致 |
| 10010009 | API key not found | API key 不存在 | 驗證 API key 是否正確 |
| 10010010 | API key expired | API key 已過期 | 聯繫管理員更新 API key |
| 10010011 | Timestamp expired | 請求時間戳超出允許範圍 | 確保系統時間同步,重新生成時間戳 |
| 10010012 | Missing required header | 缺少認證標頭 | 確保包含所有必需標頭 |
| 401 | Unauthorized | 認證失敗 | 檢查 API key 和簽名 |
| 403 | Forbidden | 無權限訪問資源 | 聯繫管理員驗證權限 |
安全最佳實踐
API Key 管理
安全存儲
- 永不在源代碼中硬編碼 API key
- 使用環境變量或安全配置管理
- 定期輪換 API key
訪問控制
- 為不同環境使用不同的 API key(開發、測試、生產)
- 如可能,實施 IP 白名單
- 監控 API key 使用並設置警報
Secret 保護
- 永不在客戶端代碼中暴露 API secret
- 永不在應用日誌中記錄 API secret
- 所有 API 通信使用 HTTPS
簽名生成
時間戳驗證
- 確保系統時間與 NTP 服務器同步
- 適當處理時鐘偏差
- 為重試請求重新生成簽名
參數一致性
- 簽名生成後不要修改請求參數
- GET 請求保持參數順序
- 簽名生成後避免格式化 JSON body
錯誤處理
- 為失敗請求實施指數退避
- 記錄簽名驗證失敗以便調試
- 時間戳過期時不要使用相同簽名重試
故障排除
問題:簽名驗證失敗
可能原因:
- API secret 不正確
- 參數順序不匹配
- JSON body 格式差異
- 時間戳格式不正確
解決方案:
- 驗證 API secret 是否正確
- 在哈希前記錄簽名字串
- 確保請求 body 與簽名 body 完全匹配
- 使用毫秒時間戳(非秒)
問題:時間戳過期
可能原因:
- 系統時鐘未同步
- 請求發送時間過長
- 重用舊簽名
解決方案:
- 與 NTP 同步系統時間
- 為每個請求生成新簽名
- 減少網絡延遲
問題:API key 未找到
可能原因:
- API key 不正確
- API key 已刪除或過期
- 環境錯誤
解決方案:
- 從管理面板驗證 API key
- 檢查是否使用正確環境(測試 vs 生產)
- 如 key 丟失請聯繫管理員