Java通过反射技术实现串MD5签名的详细教程(附代码)
一、前言
我们在日常开发过程中,常常会碰到数据传输。为了保证数据的唯一性,我们需要生成一个签名和数据一起发送,对方获取数据后也通过同样的算法进行签名,然后对比两边的签名是否一致。如果一致则认为数据没有被串改或者是否为合法的数据,否则就是非法数据。
一般使用的模型各参数的值和名字拼起来,将name转成小写后按照字典(a-z)进行排序,得到一个字符串如下:name1+value1+&+string2+value2
然后加入私钥(一个双方约定的key)得到:name1+value1+&+string2+value2+&+key
最后使用md5函数生成一个sign串,这就是该字符串的md5签名。
注意:一般空值或者list类型数据不进行签名,这个自己排除掉。
二、代码示例
以下是整理好的代码。
首先通过反射拿出object字段的name和值,按照字典排序,再进行字符串拼接,最后使用md5函数进行签名。
public class SignUtil{
public static String signIt(Object object, Class<?> clazz, String key) {
Logger logger = LoggerFactory.getLogger(SignUtil.class);
//签名算法:
if (object == null) {
return null;
}
//首先获取所有key,顺便转成map,方便存储
List<String> keys = new ArrayList<>();
Map<String, Object> tmpMap = new HashMap<>();
Field[] fields = clazz.getFields();
for (Field f : fields) {
if (!f.getName().equalsIgnoreCase("sign") && !f.getName().equalsIgnoreCase("list")) {
try {
f.setAccessible(true);
Object value = f.get(object);
if (value != null && !"".equals(value.toString())) {
keys.add(f.getName());
tmpMap.put(f.getName(), f.get(object));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
logger.debug("Generated tmpMap: {}", tmpMap);
logger.debug("Generate keys list: {}", keys);
//对key按照字典排序
Collections.sort(keys);
//拼接URL字符串
List<String> keyValuePair = new ArrayList<>();
for (String key : keys) {
Object obj = tmpMap.get(key);
String value = null;
if (obj != null) {
value = obj.toString();
}
if (StringUtils.isEmpty(value)) {
//空参数不参与签名
continue;
}
keyValuePair.add(key + "=" + value);
// try {
// keyValuePair.add(key + "=" + URLEncoder.encode(value, "utf-8"));
// } catch (UnsupportedEncodingException e) {
// logger.error("URL编码异常,原文:{}", value);
// e.printStackTrace();
// }
}
String stringA = StringUtils.join(keyValuePair, "&");
logger.debug("签名前参数内容:{}", stringA);
logger.debug("URL编码结果:{}", stringA);
String stringSignTemp = stringA + "&key=" + key;
logger.debug("需要md5的字符串:{}", stringSignTemp);
String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
logger.debug("MD5签名结果:{}", signValue);
return signValue;
}
}
其中:
1、!f.getName().equalsIgnoreCase("sign") && !f.getName().equalsIgnoreCase("list")
为object中不参与签名的字段,读者可以根据自己的需求进行添删。
2、注释的代码:
// try {
// keyValuePair.add(key + "=" + URLEncoder.encode(value, "utf-8"));
// } catch (UnsupportedEncodingException e) {
// logger.error("URL编码异常,原文:{}", value);
// e.printStackTrace();
// }
是对value值进行编码,因为有些中文需要在不同的编码中表现的值不同,所以导致签名也不通。
注意:DigestUtils.md5Hex 为站长工具类的函数,自己可以去网上查找响应的函数。