# 认证机制
## 认证流程
```
客户端请求 → 验证签名 → 验证时间戳 → 验证Nonce → 频率限制 → 处理业务 → 返回响应
```
## 必需参数
每个 API 请求都必须包含以下认证参数:
| 参数名 | 类型 | 长度 | 必需 | 描述 |
|--------------|--------|-------|----|-----------------------|
| `access_key` | string | 10-50 | ✅ | 访问密钥,格式:ak_xxxxxxxxxx |
| `timestamp` | int | 10 | ✅ | Unix 时间戳(秒) |
| `nonce` | string | 8-128 | ✅ | 随机字符串,建议使用 UUID |
| `signature` | string | 64 | ✅ | HMAC-SHA256 签名(十六进制) |
## 签名算法详解
### 第一步:构造签名字符串
```
签名字符串 = HTTP方法 + 请求路径 + timestamp + nonce + 规范化参数
```
### 第二步:规范化参数
1. 排除 `signature` 参数
2. 将剩余参数按字母顺序排序
3. 使用 `=` 连接键值对
4. 使用 `&` 连接多个参数
**示例**:
```
原始参数: {
"access_key": "ak_test123",
"card_no": "CARD123456789",
"nonce": "test123",
"signature": "abc123",
"timestamp": "1730619000"
}
规范化后: access_key=ak_test123&card_no=CARD123456789&nonce=test123×tamp=1730619000
```
### 第三步:生成签名
```bash
# 使用 OpenSSL 生成签名
signature = HMAC-SHA256(签名字符串, secret_key)
```
### 完整示例代码
使用 Python:
```python
import hmac
import hashlib
import time
import uuid
def generate_signature(method, path, params, secret_key):
# 1. 排除签名参数,按字母顺序排序
sorted_params = "&".join(
f"{k}={v}" for k, v in sorted(params.items())
if k != 'signature'
)
# 2. 构造签名字符串
sign_str = f"{method}{path}{params['timestamp']}{params['nonce']}{sorted_params}"
# 3. HMAC-SHA256 签名
return hmac.new(
secret_key.encode(),
sign_str.encode(),
hashlib.sha256
).hexdigest()
# 使用示例
params = {
'access_key': 'ak_test123',
'timestamp': str(int(time.time())),
'nonce': str(uuid.uuid4()),
}
signature = generate_signature('GET', '/api/v1/heartbeat', params, 'sk_test456')
print(f"生成签名: {signature}")
```
## 签名验证失败排查
1. **检查时间戳**
- 确保时间戳在当前时间的 ±300 秒内
- 检查服务器时间是否准确同步
2. **检查参数顺序**
- 确保所有参数按字母顺序排序
- 确保排除 signature 参数
3. **检查密钥**
- 确认 SecretKey 正确无误
- 检查是否有前导或后缀空格
4. **检查编码**
- 确保使用 UTF-8 编码
- 检查特殊字符是否正确转义
## 请求格式说明
### GET 请求
- **参数传递**: 通过 URL Query String 传递
- **示例**: `/api/v1/info?card_no=CARD123&access_key=ak_xxx×tamp=1234567890&nonce=abc123&signature=xyz789`
- **注意**: GET 请求不需要设置 Content-Type 头
### POST 请求
- **支持格式**:
- `application/json` (推荐)
- `application/x-www-form-urlencoded`
- **JSON 格式优势**:
- 更清晰的参数结构
- 更好的错误提示
- 支持复杂数据类型
- 便于参数验证
- **签名计算**: 两种格式的签名算法相同,都需要对参数进行排序和拼接
### 请求头设置
```bash
# JSON 格式
Content-Type: application/json
# Form 格式
Content-Type: application/x-www-form-urlencoded
# 通用请求头(建议)
User-Agent: YourAppName/1.0
X-Request-ID: unique-request-id
```