利用fastJson保证数据字段顺序做api数据签名加密
原创 2020-01-08 17:28 阅读(1855)次
我们在开发api接口时,尤其是开放给第三方使用的接口,通常会对接口参数做签名加密校验。我看了下大部分人都只是把url上的参数放到TreeMap中做加密:
import org.apache.commons.codec.digest.DigestUtils;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.TreeMap;
/**
* @Author: rongrong
* @Date: 2018/4/23
* @Description:
*/
public class MD5Utils {
private static void getDigest(TreeMap<String, String> map, String key, String charset){
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : map.entrySet()) {
sb = sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
sb.append("key").append("=").append(key);
System.out.println("拼接后的字符:"+sb.toString());
String sign = DigestUtils.md5Hex(getContentBytes(sb.toString(), charset));
System.out.println("加密后的签名:"+sign);
}
private static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
public static void main(String[] args) {
//treeMap默认是key升序排序 ,如果需要降序,可以使用Comparator中的compare方法
TreeMap<String,String> map = new TreeMap<String, String>();
map.put("name", "zychen");
map.put("password", "123456");
map.put("project", "base");
map.put("tenantId", "192319387131");
getDigest(map, "helloWorld","utf-8");
}
}
像上面签名方法只是做简简单单的数据签名,TreeMap只有一层数据结构,对于复杂的嵌套的数据结构,比如TreeMap中还是List,List还有Map这种数据结构,上面的签名方法就不行了,它无法保证TreeMap中list里的Map也是顺序的,就会出现签名结果没办法保证两次加密结果一致,例如如下要对这种复杂的数据签名: Map m = new HashMap();
m.put("cx",1);
m.put("x",1);
m.put("cc",1);
m.put("cT",1);
m.put("ct",1);
List<Map> list = new ArrayList();
Map m1 = new HashMap();
m1.put("cX", 1);
m1.put("cx", 1);
m1.put("ac", 1);
m1.put("b", 1);
Map m2 = new HashMap();
m2.put("cx", 1);
m2.put("cX", 1);
m2.put("ac", 1);
m2.put("b", 1);
list.add(m1);
list.add(m2);
m.put("a",list);
那有没有办法对这种复杂的数据进行签名呢?
当然有,我们也不需要对嵌套的结构进行解析就可以做到,那就是可以使用fastjson生成顺序的json,这样就可以保证两次签名一致了,要把上面的Map m数据签名加密,具体代码如下:
String json = JSON.toJSONString(m);
TreeMap parseObject = JSON.parseObject(json, TreeMap.class, Feature.OrderedField);
json = JSON.toJSONString(parseObject);//排序后的json
这样就可以拿到所有字段是排序过的json了,这样再拿去签名就可以了。
解释一下:JSON.parseObject(json, TreeMap.class, Feature.OrderedField);中的TreeMap是为了保证最外层的map是顺序的,Feature.OrderedField是设置fastJson在生成json时嵌套的字段也是排序的。