🔥 签名算法
签名生成的通用步骤如下:
- 第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
- 参数名ASCII码从小到大排序(字典序);
- 如果参数的值为空不参与签名;
- 参数名区分大小写;
- 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
- 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
- 第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。 注意:密钥的长度为32个字节
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Slf4j
public class SignatureUntils {
public static final String KEY="0de034fa56cf0ce676570d571de2705b";
private static String handleStr(Map<String,?> paramsMap){
Set<String> keySet = paramsMap.keySet();
List<String> paramNames = new ArrayList<String>(keySet);
Collections.sort(paramNames);
StringBuilder paramNameValue = new StringBuilder();
for (String paramName : paramNames ) {
if("sign".equals(paramName) || ObjectUtils.isEmpty(paramsMap.get(paramName))) {
continue;
}else{
paramNameValue.append(paramName).append("=").append(paramsMap.get(paramName)).append("&");
}
}
return paramNameValue.toString();
}
static public String signForInspiry(Map<String,?> params, String key) {
String str = handleStr(params);
StringBuffer sbkey = new StringBuffer(str);
sbkey = sbkey.append("key=" + key);
String sign = toMd5(sbkey.toString()).toUpperCase();
return sign;
}
public static String toMd5(String str) {
String re = null;
byte encrypt[];
try {
byte[] tem = str.getBytes();
MessageDigest md5 = MessageDigest.getInstance("md5");
md5.reset();
md5.update(tem);
encrypt = md5.digest();
StringBuilder sb = new StringBuilder();
for (byte t : encrypt) {
String s = Integer.toHexString(t & 0xFF);
if (s.length() == 1) {
s = "0" + s;
}
sb.append(s);
}
re = sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return re;
}
public static boolean checkSign(String sign,Map<String,?> params,String key){
try {
String signValue = signForInspiry(params, key);
if (StringUtils.endsWithIgnoreCase(signValue,sign)){
log.info("验签成功");
return true;
}
} catch (Exception e) {
log.info("验签异常");
e.printStackTrace();
}
log.info("验签失败");
return false;
}
public static void main(String[] args) {
String sign="81AA2B818EAD40FE2D8E7E3242C14577";
String key="0de034fa56cf0ce676570d571de2705b";
Map<String,Object> map = new HashMap<>();
map.put("deviceSn","000SD50030180000001");
map.put("timestamp","1661759090226");
map.put("sign",sign);
map.put("orderNo","HMP2208310000584428263559179");
System.out.println("签名参数:"+map);
String sortPram = handleStr(map);
System.out.println("排序后参数:"+sortPram);
String signValue = signForInspiry(map, "0de034fa56cf0ce676570d571de2705b");
System.out.println("签名内容:"+signValue);
checkSign(sign, map, key);
}
}