一 点睛
签名和验证签名常常用于 络安全,在此提供一个工具类。
二 代码
package com.imooc.demo.common.util;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentException;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.*;
import java.util.Map.Entry;
/**
* @className: SignatureUtils
* @description: 签名和验证签名工具类
* @date: 2020/8/21
* @author: cakin
*/
public class SignatureUtils {
/**
* 签名,MD5.
*
* @param paramMap 参数Map,不包含商户秘钥且顺序确定
* @param key 商户秘钥
* @return 签名串
*/
public static String sign(Map paramMap, String key) {
if (key == null) {
throw new RuntimeException(“key不能为空”);
}
String sign = createSign(paramMap, key);
return sign;
}
/**
* 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*
* @param paramMap 参数Map,不包含商户秘钥且顺序确定
* @param key 商户秘钥
* @return 签名串
*/
private static String createSign(Map paramMap, String key) {
StringBuffer sb = new StringBuffer();
SortedMap sort = new TreeMap(paramMap);
Set> es = sort.entrySet();
Iterator> it = es.iterator();
while (it.hasNext()) {
Entry entry = (Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !””.equals(v) && !”null”.equals(v) && !”sign”.equals(k) && !”key”.equals(k)) {
sb.append(k + “=” + v + “&”);
}
}
sb.append(“key=” + key);
System.out.println(“HMAC source:{” + sb.toString() + “}”);
// 签名
String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
System.out.println(“HMAC:{” + sign + “}”);
return sign;
}
/**
* 验证签名, 仅支持MD5.
*
* @param paramMap 参数Map,不包含商户秘钥且顺序确定
* @param key 商户秘钥
* @param sign 签名串
* @return 验签结果
*/
public static boolean checkSign(Map paramMap, String key, String sign) {
if (key == null) {
throw new RuntimeException(“key不能为空”);
}
if (sign == null) {
throw new RuntimeException(“需要验签的字符为空”);
}
return sign.equals(sign(paramMap, key));
}
/**
* 通过request获取签名Map
*
* @param request 请求
* @return 签名Map
*/
public static Map getSignMap(HttpServletRequest request) {
Map paramMap = new HashMap();
Map map = request.getParameterMap();
Set> es = map.entrySet();
Iterator> it = es.iterator();
while (it.hasNext()) {
Entry entry = (Entry) it.next();
String k = (String) entry.getKey();
Object ov = entry.getValue();
String v = “”;
if (ov instanceof String[]) {
String[] value = (String[]) ov;
v = value[0];
} else {
v = ov.toString();
}
paramMap.put(k, v);
}
return paramMap;
}
/**
* 通过url获取签名Map
*
* @param url 请求地址
* @return 签名Map
*/
@SuppressWarnings(“deprecation”)
public static Map getSignMap(String url) {
Map paramMap = new HashMap();
url = url.substring(url.indexOf(” + 1);
String[] params = url.split(“&”);
for (int i = 0; i
String param = params[i];
if (param.indexOf(“=”) != -1) {
String[] values = param.split(“=”);
if (values != null && values.length == 2) {
//update—-begin—author:scott—-date:20160115—-for:昵称转码,签名问题处理—-
if (“nickname”.equals(values[0])) {
paramMap.put(values[0], URLDecoder.decode(values[1]));
} else {
paramMap.put(values[0], values[1]);
}
//update—-begin—author:scott—-date:20160115—-for:昵称转码,签名问题处理—-
}
}
}
return paramMap;
}
/**
* 从API返回的XML数据里面计算签名
*
* @param responseString API返回的XML数据
* @param key 商户秘钥
* @return 签名
* @throws DocumentException 文档异常
*/
public static String getSignFromResponseString(String responseString, String key) throws DocumentException {
Map map = XmlUtils.xmlBody2map(responseString, “xml”);
// 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
map.put(“sign”, “”);
// 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
return sign(map, key);
}
/**
* 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
*
* @param responseString API返回的XML数据字符串
* @return API签名是否合法
* @throws DocumentException 文档异常
*/
public static boolean checkIsSignValidFromResponseString(String responseString, String key) throws DocumentException {
Map map = XmlUtils.xmlBody2map(responseString, “xml”);
System.out.println(map.toString());
Object signFromAPIResponse = map.get(“sign”);
if (signFromAPIResponse == null || signFromAPIResponse == “”) {
System.out.println(“API返回的数据签名数据不存在,有可能被第三方篡改!!!”);
return false;
}
System.out.println(“服务器返回包里面的签名是:” + signFromAPIResponse);
// 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
map.put(“sign”, “”);
// 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
String signForAPIResponse = sign(map, key);
if (!signForAPIResponse.equals(signFromAPIResponse)) {
// 签名验不过,表示这个API返回的数据有可能已经被篡改了
System.out.println(“API返回的数据签名验证不通过,有可能被第三方篡改!!!”);
return false;
}
System.out.println(“恭喜,API返回的数据签名验证通过!!!”);
return true;
}
/**
* 除去Map中的空值和签名参数
*
* @param sArray 含有签名的Map
* @return 去掉空值与签名参数后的新签名Map
*/
public static Map filter(Map sArray) {
Map result = new HashMap();
if (sArray == null || sArray.size()
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (StringUtils.isEmpty(value) || key.equalsIgnoreCase(“sign”)) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*
* @param params 需要排序并参与字符拼接的Map
* @return 拼接后字符串
*/
public static String createLinkString(Map params) {
// 第一步:把字典按Key的字母顺序排序,参数使用TreeMap已经完成排序
List keys = new ArrayList(params.keySet());
Collections.sort(keys);
// 第二步:把所有参数名和参数值串在一起
StringBuilder sb = new StringBuilder();
for (String key : keys) {
String value = params.get(key);
if (!StringUtils.isEmpty(value)) {
sb.append(key).append(“=”).append(value);
}
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(“————————测试从url中提取map———————“);
String url = “http://www.saphao.com:9999/P3-Web/commonxrs/toIndex.dotId=402880ee51334a520151334c3eaf0001&openid=oR0jFt_DTsAUJebWqGeq3A1VWfRw&nickname=JEFF&subscribe=1&jwid=&sign=F5E56A64B650A98E67CCCFFF871C7133”;
Map t = getSignMap(url);
for (Entry entry : t.entrySet()) {
System.out.println(entry.getKey() + “—>” + entry.getValue());
}
System.out.println(“————————测试签名过程—————————-“);
String key = “26F72780372E84B6CFAED6F7B19139CC47B1912B6CAED753”;
Map paramMap = new HashMap();
//paramMap.put(“id”, “134”);
paramMap.put(“token”, “edb7442d8d1a00db28062ec711f64c40”);
//paramMap.put(“smsCode”, “967910”);
//paramMap.put(“loginName”, “17792516435”);
System.out.println(createSign(paramMap, key));
}
}
三 测试
————————测试从url中提取map———————
subscribe—>1
openid—>oR0jFt_DTsAUJebWqGeq3A1VWfRw
actId—>402880ee51334a520151334c3eaf0001
nickname—>JEFF
sign—>F5E56A64B650A98E67CCCFFF871C7133
————————测试签名过程—————————-
HMAC source:{token=edb7442d8d1a00db28062ec711f64c40&key=26F72780372E84B6CFAED6F7B19139CC47B1912B6CAED753}
HMAC:{B1F25B7D27EAF67126712F2F1EC50504}
B1F25B7D27EAF67126712F2F1EC50504
文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92901 人正在系统学习中 相关资源:ios签名软件-iOS工具类资源
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!