签名生成方法如下：
- 对所有请求参数（不包括 signature 参数），按照参数名ASCII码表升序顺序排序。如：foo=1， bar=2， foo_bar=3， baz=4 排序后的顺序是 bar=2， baz=4， foo=1， foobar=3。
- 将排序好的参数名和参数值构造成字符串，格式为：key1+value1+key2+value2… 。根据上面的示例得到的构造结果为：bar2baz4foo1foobar3 。
- 选择与 secretId 配对的 secretKey ，加到上一步构造好的参数字符串之后，如 secretKey=6308afb129ea00301bd7c79621d07591
 ，则最后的参数字符串为 bar2baz4foo1foobar36308afb129ea00301bd7c79621d07591。
- 把上一步拼装好的字符串采用 utf-8 编码，使用 MD5 算法对字符串进行摘要，计算得到 signature 参数值（小写），将其加入到接口请求参数中即可。MD5 是128位长度的摘要算法，用十六进制表示，一个十六进制的字符能表示4
个位，所以签名后的字符串长度固定为32个十六进制字符。

签名生成示例代码：

<md-tab>
<md-pane md-title="Java">

```java
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;

// 注：您可以根据自己工程的实际情况，选择合适的辅助工具。
// 依赖 Apache Commons Codec（commons-codec: commons-codec）
import org.apache.commons.codec.digest.DigestUtils;
// 依赖 Apache Commons Lang（org.apache.commons: commons-lang3）
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 生成签名信息
 * @param secretKey 产品私钥
 * @param params 接口请求参数名和参数值map，不包括signature参数名
 */
public static String genSignature(String secretKey, Map<String, String> params) {
    String[] paramNames = params.keySet().toArray(new String[0]);
    Arrays.sort(paramNames);

    StringBuilder sb = new StringBuilder();
    for (String name : paramNames) {
        String value = ObjectUtils.defaultIfNull(params.get(name), StringUtils.EMPTY);
        sb.append(name).append(value);
    }

    sb.append(secretKey);

    return DigestUtils.md5Hex(sb.toString().getBytes(StandardCharsets.UTF_8));
}
```

</md-pane>

<md-pane md-title="C#">

```csharp
using System;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Linq;

// 注：通常，你会创建一个 Dictionary 对象作为 paramDict
public static string GenSignature(string secretKey, IEnumerable<KeyValuePair<string, string>> paramDict)
{
    StringBuilder sb = new StringBuilder();
    foreach (var param in paramDict.OrderBy(p => p.Key, StringComparer.Ordinal)) {
        var name = param.Key; 
        var value = param.Value ?? String.Empty;
        sb.Append(name).Append(value);
    }

    sb.Append(secretKey);

    using (MD5 md5 = MD5.Create())
    {
        var md5Bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()));
        return String.Concat(md5Bytes.Select(c => c.ToString("x2")));
    }
}
```

</md-pane>
<md-pane md-title="JS">

```js
// 注：你可以根据自己工程的实际情况，选择合适的辅助工具。
const crypto = require('crypto');

var genSignature = function (secretKey, paramDict) {
    var sortedNames = Object.keys(paramDict).sort();

    var paramStr = '';
    for (var i=0; i<sortedNames.length; i++) {
        var name = sortedNames[i];
        paramStr += name + (paramDict[name] || '');
    }

    paramStr += secretKey;

    return crypto.createHash('md5')
        .update(paramStr, "UTF-8")
        .digest('hex');
};
```

</md-pane>
<md-pane md-title="Python">

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hashlib

"""生成签名信息
Args:
    secret_key 产品私钥
    param_dict 接口请求参数，不包括signature参数
"""
def gen_signature(secret_key, param_dict):
  param_str = ''.join([
    str(name) + str(param_dict[name] or '')
    for name
    in sorted(param_dict.keys())
    ])

  param_str += secret_key

  return hashlib.md5(param_str.encode("utf-8")).hexdigest()
```

</md-pane>
<md-pane md-title="PHP">

```PHP
/**
 * 生成签名信息
 * $secret_key 产品私钥
 * $params 接口请求参数，不包括signature参数
 */
function gen_signature($secret_key, $params) {
    ksort($params);

    $tmp_array = array_map(
        function ($value, $name) { return $name . ($value ?: ''); },
        $params,
        array_keys($params));

    $tmp_str = implode($tmp_array);

    $tmp_str .= $secret_key;

    return md5(mb_convert_encoding($tmp_str, "UTF-8"));
}
```

</md-pane>
</md-tab>