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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值