# 签名(sign)算法

签名(sign)算法描述如下：

* 1、按照请求参数名ASCII码升序排列非空请求参数（字典序）,使用URL键值对的格式,（即key1=value1&key2=value2…）拼接成字符串`StringParm`；
* 2、在`StringParm`最后拼接上`secret`得到字符串`StringParmSign`；
* 3、再对`StringPaemSign`进行`sha1`运算，并将得到的字符串所有的字符转换为大写，得到最终`sign`；
* 4、该签名值使用sign系统级参数一起和其它请求参数一起发送给服务开放平台。

**注意：接收回调通知的签名计算不需要加入appkey，仅API调用需要**

假如这些业务级参数和系统级参数的值如下表所示：

| 系统级参数名称 | 参数值 | 业务级参数名称 | 参数值 |
| ------- | --- | ------- | --- |
| appkey | 000001 | userName | wx |
| timestamp | 1556595508 | age | 24 |
| nonce | 24523 | sex | 1 |

根据签名算法，首先按参数名称ASCII码升序将所有参数名和参数值拼装成一个字符串：
age=24&appkey=000001&nonce=24523&sex=1&timestamp=1556595508&username=wx
假设，appkey为 000001的secret（应用密钥）是 `"a1b1c1d1"`，则将`"a1b1c1d1"` 将参数添加到以上请求参数的最后，得到：
age=24&appkey=000001&nonce=24523&sex=1&timestamp=1556595508&userName=wx&secret=`a1b1c1d1`
`注意secret不参与排序，不需要在接口调用中传入，只参与签名使用`
对以上字符口串进行sha1签名运算，并且将字符串字符转换为大写，得到：
`963A56BAEBED746F2746E4D9B3B77BE0F2E171E7`
最后，客户端的可对每个业务的URL地址（格式如：`baseURL/api/v1/xxx/xxx`），以POST请求方式使用如下的报文（JSON格式）对服务方法发起请求：
```json
POST baseURL/api/具体接口地址(不要拼接参数) HTTP/1.1
Content-Type: application/json;charset=utf-8

{
    "appkey": "000001",
    "timestamp": 1556595508,
    "nonce": 24523,
    "sign": "963A56BAEBED746F2746E4D9B3B77BE0F2E171E7",
    "userName": "wx",
    "age": "24",
    "sex": "1"
}
```
Java生成签名代码示例：
```java
// JAVA生成签名代码示例
private static String generateSign(Map<String, Object> paramMap, String secret) {
    List<String> list = new ArrayList<>(20);
    for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
        list.add(entry.getKey() + "=" + entry.getValue() + "&");
    }
    Collections.sort(list);
    String signParam = String.join("", list);
    String param = signParam + "secret=" + secret;
    return DigestUtils.sha1Hex(param).toUpperCase();
}
```
