要求
- 首先,排除sign参数之外,将其它参数(空值除外)按名称进行字母排序,并和它的取值一起组成name=value样式的字符串,然后用&把它们拼装为一个大字符串,对于嵌套的参数,嵌套的参数列表也需按照字母排序进行拼装。
a) 比如,要传递下列参数
i.version=1.0.0
ii.return_code=0
iii.拼装之后的字符串为:return_code=0&version=1.0.0
b) 比如,要传递下列参数
i.a=1
ii.b={“d”:”3”,”c”:”2”}
iii.拼装之后的字符串为:a=1&b=c=2&d=3
c)比如,要传递下列参数
i.a=1
ii.b=[{“d”:”3”,”c”:”2”},{“d”:”5”,”c”:”4”}]
iii.拼装之后的字符串为:a=1&b=c=2&d=3&c=4&d=5
d)比如,要传递下列参数
i.a=1
ii.b=[“2”,”3”]
iii.拼装之后的字符串为:a=1&b=2&3
e)比如,要传递下列参数
i.a=1
ii.b=[[{“d1”:”1”,”c1”:”2”},{“d2”:”3”,”c2”:”4”}],[{“d3”:”5”,”c3”:”6”},{“d4”:”7”,”c4”:”8”}]]
iii.拼装之后的字符串为:a=1&b=c1=2&d1=1&c2=4&d2=3&c3=6&d3=5&c4=8&d4=7- 在上述拼装之后的字符串后面直接拼装accesskey的值。
a)比如,上述参数return_code=0&version=1.0.0,假设accesskey是123456789ABCDEF,拼装以后,成为下述字符串:
b)return_code=0&version=1.0.0123456789ABCDEF- 对上述第2步得到的字符串,进行MD5运算(32位大写),得到sign
package cn.hkrt.haipay.common.utils;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.MessageDigest;
import java.util.*;
/**
* 签名工具类,按字母升序排列,拼接key
* @author zhaoyilong
*
*/
public class SignUtils {
private static BouncyCastleProvider provider = new BouncyCastleProvider();
/**
* 直接拼接key在最后面
* 例:key=123456789的时候待签名的字符串为,aa=3&bb=1&cc=1&dd=20160426999123456789
* @param partnerKey
* @param params
* @return
*/
public static String signParams(String partnerKey,Map params){
//直接拼接key
String tobesign = getToBeSign(params) + partnerKey;
return md5dataToSign(tobesign);
}
public static String md5dataToSign(String data){
String algorithm = "MD5";
try {
//BouncyCastleProvider provider = new BouncyCastleProvider();
MessageDigest md = MessageDigest.getInstance(algorithm, provider);
byte[] rtn = md.digest(data.getBytes("UTF-8"));
return byte2Hex(rtn).toUpperCase();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("不支持的算法:"+algorithm);
}
}
public static String getToBeSign(Map params){
TreeMap tm = new TreeMap();
tm.putAll(params); //参数排序
Set set = tm.entrySet();
StringBuffer sb = new StringBuffer();
int i = 0;
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
Map.Entry e = (Map.Entry) iterator.next();
String k = (String)e.getKey();
//String v = (String)e.getValue();
if(e.getValue() == null || "".equals(e.getValue()) || "sign".equals(k) || "mac".equals(k)){
continue;
}
String v = "";
if(e.getValue() instanceof JSONArray){
v = getJsonArrayStr((JSONArray)e.getValue());
}else if(e.getValue() instanceof JSONObject){
v = getToBeSign((JSONObject)e.getValue());
}else{
v = e.getValue().toString();
}
if(i != 0){
sb.append("&");
}
sb.append(k+"="+v);
i = i + 1;
}
return sb.toString();
}
public static String getJsonArrayStr(JSONArray a){
String r = "";
for(int j=0; j < a.size() ; j++){
Object b = (Object) a.get(j);
String v = "";
if(b instanceof JSONArray){
v = getJsonArrayStr((JSONArray)b);
}else if(b instanceof JSONObject){
v = getToBeSign((JSONObject)b);
}else{
v = b.toString();
}
if(j ==0){
r = v;
}else{
r += "&" + v;
}
}
return r;
}
public static String byte2Hex(byte[] b) {
StringBuilder sb = new StringBuilder();
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
sb.append("0").append(stmp);
} else {
sb.append(stmp);
}
}
return sb.toString().toUpperCase();
}
}