# 接口签名算法说明

## 概述

本接口使用 **HMAC-MD5** 算法对请求参数进行签名，以确保请求的合法性与完整性，防止请求被篡改或伪造。
生成的sign值放在header中，key=X-sign，value=加密值。

---

## 签名生成流程

```
请求参数
    │
    ▼
① 参数递归排序（ksort）
    │
    ▼
② 构造签名字符串（key=value&key=value...）
    │   数组/对象类型 → JSON 字符串
    ▼
③ HMAC-MD5(query_string, secret_key)
    │
    ▼
sign（签名结果）
```

---

## 详细步骤

### 第一步：参数递归排序

对所有请求参数按照**键名字典序（ksort）进行递归排序**，嵌套数组也需同样处理，以保证双方构造字符串的顺序一致。

### 第二步：构造签名字符串

遍历排序后的参数，按以下规则拼接为字符串：

| 参数类型                 | 处理方式                                                 |
| ------------------------ | -------------------------------------------------------- |
| 普通值（字符串、数字等） | 直接使用原始值                                           |
| 数组 / 对象              | 转为 JSON 字符串（中文不转义，`JSON_UNESCAPED_UNICODE`） |

拼接格式：

```
key1=value1&key2=value2&key3=value3
```

> ⚠️ **注意**：参数值**不做 URL encode**，与 `http_build_query` 的行为不同。数组参数也**不展开**为 `key[0]=...` 形式，而是整体转为 JSON 字符串。

### 第三步：计算签名

使用 `secret_key` 对上一步得到的字符串执行 **HMAC-MD5** 计算：

```
sign = HMAC-MD5(query_string, secret_key)
```

---

## 示例

### 原始请求参数

```json
{
  "uid": 1001,
  "amount": 100,
  "currency": "CNY",
  "items": [
    { "id": 1, "name": "商品A" }
  ]
}
```

### 第一步：排序后的参数顺序

```
amount, currency, items, uid
```

### 第二步：构造签名字符串

```
amount=100&currency=CNY&items=[{"id":1,"name":"商品A"}]&uid=1001
```

### 第三步：计算签名

```
sign = HMAC-MD5("amount=100&currency=CNY&items=[{\"id\":1,\"name\":\"商品A\"}]&uid=1001", "your_secret_key")
```

---

## 注意事项

| 项目     | 说明                                                     |
| -------- | -------------------------------------------------------- |
| 排序方式 | 字典序递归排序，嵌套数组也要排序                         |
| 数组参数 | 转为 JSON 字符串，中文不转义（`JSON_UNESCAPED_UNICODE`） |
| URL 编码 | 参数值**不做** URL encode                                |
| 数组展开 | **不展开**为 `key[0]=...` 形式                           |
| 密钥管理 | `secret_key` 需双方提前约定，**严禁在请求中传输**        |
| 算法     | HMAC-MD5，输出为 32 位十六进制小写字符串                 |

---

密钥： H6p*2RfEu4ITcL

