原创

Java 调用微信接口生成签名串源码剖析

签名机制把需要参与签名的参数放入数组中,对数组里的每一个参与签名的参数从a到z的顺序排序,若遇到相同首字母,则看第二个字母,以此类推。排序完成之后,再把所有数组值以“&”字符连接起来,这串字符串便是待签名字符串。例如:

http://www.yoodb.com?id=79&return_url=http%3A%2F%2Fwww.baidu.com&sign=B7A7D78E1B8693B032EEFE7E8A8A5B1B。

import java.security.MessageDigest;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

public class SignUtil {
	/**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    public String createSign(SortedMap<String, String> packageParams) throws Exception {
StringBuffer sb = new StringBuffer();
Set<?> es = packageParams.entrySet();
Iterator<?> it = es.iterator();
while (it.hasNext()) {
    Map.Entry entry = (Map.Entry) it.next();
    String k = (String) entry.getKey();
    String v = (String) entry.getValue();
    if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
    }
}
sb.append("key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
String sign = MD5Encode(sb.toString()).toUpperCase();
return sign;
    }
    
    /**
     * MD5编码
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    private static String MD5Encode(String origin) {
String resultString = null;
try {
    resultString = origin;
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(resultString.getBytes("UTF-8"));
    resultString = byteArrayToHexString(md.digest());
} catch (Exception e) {
    e.printStackTrace();
}
return resultString;
    }
    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    private static String byteArrayToHexString(byte[] b) {
StringBuilder resultSb = new StringBuilder();
for (byte aB : b) {
    resultSb.append(byteToHexString(aB));
}
return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
    n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
    }
    
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f"};
    
    public static void main(String[] args) throws Exception {
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("id", "XXXXXXXXXXXXXXXXXXXX");
		packageParams.put("return_url", "http://www.baidu.com");
		String str = new SignUtil().createSign(packageParams);
		System.out.println(str);
	}
}

根据HTTP协议要求,传递参数的值中如果存在特殊字符(如:&、@等),那么该值需要做URL Encoding,这样请求接收方才能接收到正确的参数值。这种情况下,待签名数据应该是原生值而不是encoding之后的值。

在MD5签名时,需要安全校验码(key)参与签名,当拿到请求时的待签名字符串后,需要把安全校验码(key)直接拼接到待签名字符串后面,形成新的字符串。利用MD5的签名函数对这个新的字符串进行签名运算,从而得到32位签名结果字符串。

~阅读全文-人机检测~

微信公众号“Java精选”(w_z90110),专注Java技术干货分享!让你从此路人变大神!回复关键词领取资料:如Mysql、Hadoop、Dubbo、Spring Boot等,免费领取视频教程、资料文档和项目源码。微信搜索小程序“Java精选面试题”,内涵3000+道Java面试题!

涵盖:互联网那些事、算法与数据结构、SpringMVC、Spring boot、Spring Cloud、ElasticSearch、Linux、Mysql、Oracle等

评论

分享:

支付宝

微信