Skip to content

统一签名规则

统一签名规则

注意:仅适用于 openapi/v2/...等相关接口

appkey、appsecret、connectNo需要向管理员申请并向管理员提供访问ip白名单

签名规则

固定位置参数:SignatureStr=timestamp+“&&”+appkey+“&&”+appsecret +“&&”+ noncestr

其他请求参数:SignatureStr再拼接上请求参数按照参数名(Key)进行升序排列,将排序后参数值(value)拼装成字符串后进行MD5签名。

💡 注意:签名需要忽略值为空字段和为0字段。

例如:

请求参数为:connectNo=6119f77eb77d2e6d0b50e28a&accountId=123123

那么

Signature=md5(SignatureStr + “&&123123&&6119f77eb77d2e6d0b50e28a”)

请求参数

编号字段类型说明是否必须
1appkeyString管理员提供
2timestampString13位时间戳(毫秒)
3signatureString签名
4noncestrString随机字符串(32位以内)

代码示例

java代码样例

java
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class Test {

  // 必传
  private static String timestamp = System.currentTimeMillis() + "";
  private static String noncestr = timestamp;
  private static String appkey = "";
  // 不传
  private static String appsecret = "";
  private static String connentNo = "";
  private static String HOST = "";


  public static void main(String[] args) {
    testRequestAccountDetail();
  }

  // 用户信息接口(accountId参与签名样例)
  public static void testRequestAccountDetail() {
    String accountId = "618b20c56304402aefa07c50";
    // 生成签名
    Map<String, String> map = new HashMap<>();
    map.put("connectNo", connentNo);
    map.put("sessionId", "618b20c56304402aefa07c51");
    // map.put("accountId", accountId); // 是否添加到签名
    map.put("signature", signature(timestamp, appkey, appsecret, noncestr, map));
    // 公共参数
    map.put("timestamp", timestamp);
    map.put("appkey", appkey);
    map.put("noncestr", noncestr);
    String url = HOST + "/openapi/v2/" + accountId + "/detail?";
    System.out.println(url + getMapUrl(map));
  }

  /*
   * @param timestamp 时间戳
   * @param appkey    管理员提供的key
   * @param appsecret 管理员提供的secret
   * @param noncestr  随机数
   * @param resMap 所有参数MAP集合(不包含appsecret)
   * @return
   */
  private static String signature(String timestamp, String appkey, String appsecret,
      String noncestr, Map<String, String> resMap) {
    //移除key
    resMap.remove("appkey");
    //移除时间戳
    resMap.remove("timestamp");
    //移除随机数
    resMap.remove("noncestr");
    //移除签名
    resMap.remove("signature");

    // 1. 参数名按照ASCII码表升序排序
    String[] keys = resMap.keySet().toArray(new String[0]);
    Arrays.sort(keys);
    // 2. 按照排序拼接参数名与参数值
    StringBuffer paramBuffer = new StringBuffer();
    for (String key : keys) {
      if (StringUtils.hasLength(resMap.get(key)) && !resMap.get(key).equals("0")) {
        paramBuffer.append("&&").append(resMap.get(key) == null ? "" : resMap.get(key));
      }
    }
    String rawSignatureString =
        String.format("%s&&%s&&%s&&%s", timestamp, appkey, appsecret, noncestr)
            + paramBuffer.toString();
    log.info("appkey:" + appkey + ">>>>>用户应加密串顺序为:" + rawSignatureString);
    log.info("签名: {}", DigestUtils.md5DigestAsHex(rawSignatureString.getBytes()));
    return DigestUtils.md5DigestAsHex(rawSignatureString.getBytes(StandardCharsets.UTF_8));
  }

  // map转url
  public static String getMapUrl(Map<String, String> map) {
    StringBuilder sb = new StringBuilder();
    for (String key : map.keySet()) {
      sb.append(key).append("=").append(map.get(key)).append("&");
    }
    if (sb.length() > 0) {
      sb.deleteCharAt(sb.length() - 1);
    }
    return sb.toString();
  }

}