在日常开发中难免需要调用外部的api接口,但是一般的外部接口为了安全通常都会有签名验证,不同的服务商签名算法要求不一样,但是有一个最常见的要求:接口中每一个字段以字典顺序排序之后,按照key1=value1&key2=value2.....&access_token="令牌"的顺序,进行拼接。
不同的地方可能说法不同,有的地方是说按照参数名ASCII码从小到大排序,其实是一个意思。
签名方法一:
/**
* 接口的签名生成方法
* @param params 参数
* @param privateKey 秘钥
*/
public static String createSign(Map<String, String> params, String privateKey){
StringBuilder sb = new StringBuilder();
// 将参数以参数名的字典升序排序
Map<String, String> sortParams = new TreeMap<String, String>(params);
for (Map.Entry<String, String> entry : sortParams.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().trim();
if (!StringUtils.isEmpty(value)){
sb.append("&").append(key).append("=").append(value);
}
}
String stringA = sb.toString().replaceFirst("&","");
String stringSignTemp = stringA + "&"+"appsecret="+privateKey;
//将签名使用MD5加密并全部字母变为大写
//String signValue = Md5Utils.hash(stringSignTemp);
String signValue = Md5Utils.hash(stringSignTemp).toUpperCase();
return signValue;
}
以上方法是以TreeMap存储参数后,做的排序。因为TreeMap可以自动排序。
签名方法二:
/**
* 生成签名
* @param params 需要生成签名的参数
* @param secretKey 加密的key
* @return
*/
public static String getSign(Map<String, Object> params, String secretKey) {
Set<String> keySet = params.keySet();
String[] keyArray = keySet.toArray(new String[0]);
Arrays.sort(keyArray);
StringBuilder content = new StringBuilder();
//按要求字段"sign","sign_type","secret_key",""不参与拼接
String[] notContainArray = {"sign","sign_type","secret_key",""};
for (String key : keyArray) {
if (!Arrays.asList(notContainArray).contains(key)
&& String.valueOf(params.get(key)).length() > 0) {
content.append(key).append("=").append(params.get(key)).append("&");
}
}
content.append("key=").append(secretKey);
String str = md5( content.toString());
return str.toUpperCase();
}
以上方法是用HashMap,需要先使用Arrays.sort排序。
注:TreeMap集合默认按照键元素进行自然排序,而HashMap则不具备该特性,它依照元素的哈希值进行排序,所以展示出来的结果是乱序。