一 点睛

签名和验证签名常常用于网络安全,在此提供一个工具类。

二 代码

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 < params.length; 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() <= 0) {

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.do?actId=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签名软件_Java实现签名工具类相关推荐

  1. java 静态类 安全_Java静态static工具类线程安全问题研究

    针对静态方法有以下一些前提: 静态方法和实例方法的区别是静态方法只能引用静态变量,静态方法通过类名来调用,实例方法通过对象实例来调用 每个线程都有自己的线程栈,栈与线程同时创建,每一个虚拟机线程都有自 ...

  2. java时间随机数_java开发代码工具类(时间戳/随机数/日期等)

    简介 java开发代码工具类,提高开发效率,持续更新~ 实践 package com.springboot.sixmonth.common.util; import java.math.BigInte ...

  3. java计算工作日_Java工作日计算工具类

    工作日计算工具类 主要功能:传入两个日期,返回这两个日期之间有多少个工作日. 思路: 预先设置好一定年份范围内的节假日.补休到map里.(这里暂时只设置了2017 - 2018年的) 将这个年份范围内 ...

  4. java word生成_JAVA生成WORD工具类

    该方法借助freemarker的JAR包即可. 参考: 所需工具: 步骤: 1.在word中编辑好模版样式,设置好占位符,注意图片最好先黏上去 2.在word中,文件-另存为-XML格式 3.使用工具 ...

  5. java校验文件格式_java验证文件格式工具类(获取文件真实格式)

    , String>();privateVerifyFileType(){} static{ getAllFileType();//初始化文件类型信息} /*** Discription:[get ...

  6. java 查找一行_Java培训之工具类通用的查询一行多列,非实体

    //通用的查询方法之四:查询多行多列,但每一行又不是一个JavaBean /* * SELECT did,AVG(salary),MAX(Salary) FROM t_employee GROUP B ...

  7. java描绘条形码_java生成条形码工具类

    /** * 静态内部类 * 自定义的 TextPainter, 允许定义字体,大小,文本等 * 参考底层实现:BaseLineTextPainter.getInstance() */ protecte ...

  8. java每秒限流_java限流工具类

    代码 import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.ConcurrentHashM ...

  9. Java学习总结:58(Collections工具类)

    Collections工具类 Java提供了一个集合的工具类--Collections,这个工具类可以实现List.Set.Map集合的操作.Collections类的常用方法如下: No. 方法 类 ...

最新文章

  1. 重新建立域计算机账户与域控制器的联系
  2. c++fabs函数_二次函数背景下的菱形存在性问题
  3. 0基础学python编程难吗-对于0基础的人,直接学Python编程合适吗?
  4. 记一次Redis和NetMQ的测试
  5. modelandview使用过程_面试问烂的 Spring AOP 原理、Spring MVC 过程
  6. 关于JavaScript的变量和函数提升
  7. sourcetree帮助文档
  8. java项目流程_Java项目开发全流程实践
  9. Python-Socket编程学习(11.3)
  10. js中“||”和“”的高级用法
  11. AJAX不能访问MVC后台程序的问题
  12. Windows Phone SDK 7.1 RTM 发布
  13. Mapbox使用之glyphs(字体符号)与sprite图生成与拆分
  14. 海贼王热血航线正在连接服务器,海贼王热血航线为什么连接不了服务器?老是说人已满进不去?...
  15. 流利阅读 2019.2.22 Duke University apologizes over professor’s email asking Chinese students to speak En
  16. FamilyParty生态起航,链游版皇室战争Infinite Force打响头炮
  17. grep -A -B -C使用介绍
  18. SECS/GEM通信协议学习之报文
  19. 前端学习: 用css设置文字样式
  20. TexStudio 英文拼写检查 语法检查

热门文章

  1. LTTng中使用USDT
  2. python算术运算相关魔法方法_运算符相关的魔术方法
  3. 《那些年啊,那些事——一个程序员的奋斗史》——95
  4. Golang + Laya引擎实现的简易版“球球大作战”小游戏
  5. 商标注册申请材料有哪些?
  6. 唐铭远 受邀担任 火星少年计划 第四季 特邀小主持人
  7. 数字化校园建设规划方案
  8. symmetric funtion and antisymmetric function(对称性函数和反对称性函数)
  9. diskgenius克隆硬盘无法启动_DiskGenius官方图文教程--复制(克隆)硬盘
  10. 119.超长正整数的加法