java签名软件_Java实现签名工具类
一 点睛
签名和验证签名常常用于网络安全,在此提供一个工具类。
二 代码
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实现签名工具类相关推荐
- java 静态类 安全_Java静态static工具类线程安全问题研究
针对静态方法有以下一些前提: 静态方法和实例方法的区别是静态方法只能引用静态变量,静态方法通过类名来调用,实例方法通过对象实例来调用 每个线程都有自己的线程栈,栈与线程同时创建,每一个虚拟机线程都有自 ...
- java时间随机数_java开发代码工具类(时间戳/随机数/日期等)
简介 java开发代码工具类,提高开发效率,持续更新~ 实践 package com.springboot.sixmonth.common.util; import java.math.BigInte ...
- java计算工作日_Java工作日计算工具类
工作日计算工具类 主要功能:传入两个日期,返回这两个日期之间有多少个工作日. 思路: 预先设置好一定年份范围内的节假日.补休到map里.(这里暂时只设置了2017 - 2018年的) 将这个年份范围内 ...
- java word生成_JAVA生成WORD工具类
该方法借助freemarker的JAR包即可. 参考: 所需工具: 步骤: 1.在word中编辑好模版样式,设置好占位符,注意图片最好先黏上去 2.在word中,文件-另存为-XML格式 3.使用工具 ...
- java校验文件格式_java验证文件格式工具类(获取文件真实格式)
, String>();privateVerifyFileType(){} static{ getAllFileType();//初始化文件类型信息} /*** Discription:[get ...
- java 查找一行_Java培训之工具类通用的查询一行多列,非实体
//通用的查询方法之四:查询多行多列,但每一行又不是一个JavaBean /* * SELECT did,AVG(salary),MAX(Salary) FROM t_employee GROUP B ...
- java描绘条形码_java生成条形码工具类
/** * 静态内部类 * 自定义的 TextPainter, 允许定义字体,大小,文本等 * 参考底层实现:BaseLineTextPainter.getInstance() */ protecte ...
- java每秒限流_java限流工具类
代码 import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.ConcurrentHashM ...
- Java学习总结:58(Collections工具类)
Collections工具类 Java提供了一个集合的工具类--Collections,这个工具类可以实现List.Set.Map集合的操作.Collections类的常用方法如下: No. 方法 类 ...
最新文章
- 重新建立域计算机账户与域控制器的联系
- c++fabs函数_二次函数背景下的菱形存在性问题
- 0基础学python编程难吗-对于0基础的人,直接学Python编程合适吗?
- 记一次Redis和NetMQ的测试
- modelandview使用过程_面试问烂的 Spring AOP 原理、Spring MVC 过程
- 关于JavaScript的变量和函数提升
- sourcetree帮助文档
- java项目流程_Java项目开发全流程实践
- Python-Socket编程学习(11.3)
- js中“||”和“”的高级用法
- AJAX不能访问MVC后台程序的问题
- Windows Phone SDK 7.1 RTM 发布
- Mapbox使用之glyphs(字体符号)与sprite图生成与拆分
- 海贼王热血航线正在连接服务器,海贼王热血航线为什么连接不了服务器?老是说人已满进不去?...
- 流利阅读 2019.2.22 Duke University apologizes over professor’s email asking Chinese students to speak En
- FamilyParty生态起航,链游版皇室战争Infinite Force打响头炮
- grep -A -B -C使用介绍
- SECS/GEM通信协议学习之报文
- 前端学习: 用css设置文字样式
- TexStudio 英文拼写检查 语法检查
热门文章
- LTTng中使用USDT
- python算术运算相关魔法方法_运算符相关的魔术方法
- 《那些年啊,那些事——一个程序员的奋斗史》——95
- Golang + Laya引擎实现的简易版“球球大作战”小游戏
- 商标注册申请材料有哪些?
- 唐铭远 受邀担任 火星少年计划 第四季 特邀小主持人
- 数字化校园建设规划方案
- symmetric funtion and antisymmetric function(对称性函数和反对称性函数)
- diskgenius克隆硬盘无法启动_DiskGenius官方图文教程--复制(克隆)硬盘
- 119.超长正整数的加法