Appearance
统一签名规则
统一签名规则
注意:仅适用于 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”)
请求参数
编号 | 字段 | 类型 | 说明 | 是否必须 |
---|---|---|---|---|
1 | appkey | String | 管理员提供 | 是 |
2 | timestamp | String | 13位时间戳(毫秒) | 是 |
3 | signature | String | 签名 | 是 |
4 | noncestr | String | 随机字符串(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();
}
}