接口签名规则及Java代码demo实现

签名规则
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证接口调用传送的sign参数不参与签名,将生成的签名与该sign值作校验。
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。 注意:密钥的长度为32个字节。

1.导入jar
implementation("commons-beanutils:commons-beanutils:1.9.3")

2.MD5工具类

import java.security.MessageDigest;

public class MD5 {
private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f"}; /**
* 转换字节数组为16进制字串
* @param b 字节数组
* @return 16进制字串
*/
public static String byteArrayToHexString(byte[] b) {
StringBuilder resultSb = new StringBuilder();
for (byte aB : b) {
resultSb.append(byteToHexString(aB));
}
return resultSb.toString();
} /**
* 转换byte到16进制
* @param b 要转换的byte
* @return 16进制格式
*/
private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
} /**
* MD5编码
* @param origin 原始字符串
* @return 经过MD5加密之后的结果
*/
public static String MD5Encode(String origin) {
String resultString = null;
try {
resultString = origin;
MessageDigest md = MessageDigest.getInstance("MD5");
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
return resultString;
} }

3.实体类

import java.util.List;

public class UploadReqVO {
//手机号
private String mobile;
//姓名
private String realname;
//身份证号
private String idno;
//字符数组
private List<String> testBase64Str;
private String sign; public String getMobile() {
return mobile;
} public void setMobile(String mobile) {
this.mobile = mobile;
} public String getRealname() {
return realname;
} public void setRealname(String realname) {
this.realname = realname;
} public String getIdno() {
return idno;
} public void setIdno(String idno) {
this.idno = idno;
} public List<String> getTestBase64Str() {
return testBase64Str;
} public void setTestBase64Str(List<String> testBase64Str) {
this.testBase64Str = testBase64Str;
} public String getSign() {
return sign;
} public void setSign(String sign) {
this.sign = sign;
}
}

4.签名类及测试类

import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.tomcat.util.security.MD5Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*; public class Signature {
private static Logger log = LoggerFactory.getLogger(Signature.class); /**
* 对象入参,对象转MAP
* @param object
* @return
* @throws Exception
*/
public static String getSignNew(Object object,String key) throws Exception {
Map<String, String> map = BeanUtils.describe(object);
return getSignNew(map,key);
} public static String getSignNewArray(UploadReqVO object, String key) throws Exception {
Map<String, String> map = BeanUtils.describe(object);
//覆盖
map.put("testBase64Str", JSON.toJSONString(object.getTestBase64Str()).replace("\"",""));
return getSignNew(map,key);
} /**
* 签名
* @param map
* @return
*/
private static String getSignNew(Map<String,String> map,String key) throws Exception{
ArrayList<String> list = new ArrayList<String>();
for(Map.Entry<String,String> entry:map.entrySet()){
if(entry.getValue() != null && !StringUtils.isEmpty(entry.getValue().toString()) && !"null".equals(entry.getValue())
&& !"class".equals(entry.getKey())){ //空字符串 entry.getValue()!=""){
list.add(entry.getKey() + "=" + entry.getValue() + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
// Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); //忽略大小写
Arrays.sort(arrayToSort);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
//过滤最后一个字符串&
int lastIdx = result.lastIndexOf("&");
result = result.substring(0,lastIdx);
// result += "key=" + key; //去掉key= 字符串
result += key; //key直接拼接在后面 try{
log.info("Sign Before MD5:"+ result);
result = MD5.MD5Encode(result);
log.info("Sign Result:" + result);
}catch (Exception e) {
e.printStackTrace();
} return result;
} public static boolean checkIsSignValidFromResyponseStringObject(Object object,String key) throws Exception {
Map<String, String> map = org.apache.commons.beanutils.BeanUtils.describe(object);
return checkIsSignValidFromResponseString(map,key);
} public static boolean checkIsSignValidFromResponseStringArray(UploadReqVO object, String key) throws Exception {
Map<String, String> map = BeanUtils.describe(object);
//覆盖
map.put("testBase64Str", JSON.toJSONString(object.getTestBase64Str()).replace("\"",""));
return checkIsSignValidFromResponseString(map,key);
} /**
* object转换为map 验证签名
* @param map
* @return
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
* @throws IllegalAccessException
*/
private static boolean checkIsSignValidFromResponseString(Map<String,String> map,String key) throws Exception {
String signFromAPIResponse = null;
if(map.get("sign")!=null){
signFromAPIResponse = map.get("sign").toString();
} if(signFromAPIResponse=="" || signFromAPIResponse == null){
log.info("signFromAPIResponse报空");
return false;
} //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
map.put("sign","");
map.put("class","");
//将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
//重新签名
log.info("签名前的map="+map);
String signForAPIResponse = Signature.getSignNew(map,key);
log.info("签名后的字符串="+signForAPIResponse); if(!signForAPIResponse.equals(signFromAPIResponse)){
//签名验不过,表示这个API返回的数据有可能已经被篡改了
log.info("匹配不一致");
return false;
}
return true;
} public static void main(String[] args) {
String key = "testkey123testkey123testkey12345"; try {
UploadReqVO uploadReqVo = new UploadReqVO(); List<String> pic1List = new ArrayList<String>();
String pic5 = Base64.getEncoder().encodeToString("测试字符串1".getBytes(StandardCharsets.UTF_8));
pic1List.add(pic5);
String pic6 = Base64.getEncoder().encodeToString("测试字符串2".getBytes(StandardCharsets.UTF_8));
pic1List.add(pic6);
uploadReqVo.setTestBase64Str(pic1List); uploadReqVo.setIdno("465601200810081204");
uploadReqVo.setRealname("测试员");
uploadReqVo.setMobile("19945558899");
uploadReqVo.setSign("");
//数组方法
String signStr3 = Signature.getSignNewArray(uploadReqVo,key);
//非数组方法
// String signStr3 = Signature.getSignNew(uploadReqVo,key);
System.out.println("(上传图片)签名字符串:" + signStr3);
uploadReqVo.setSign(signStr3);
System.out.println("(上传图片)参数json=" + JSON.toJSONString(uploadReqVo)); //验证签名
//数组方法
boolean flag3 = Signature.checkIsSignValidFromResponseStringArray(uploadReqVo,key);
//非数组方法
// boolean flag3 = Signature.checkIsSignValidFromResyponseStringObject(uploadReqVo,key);
System.out.println("(上传图片)验证签名是否一致="+flag3); } catch (Exception e) {
e.printStackTrace();
} }
}
打印输出日志对比:
//数组方式
16:56:50.014 [main] INFO com.example.utils.Signature - Sign Before MD5:idno=465601200810081204&mobile=19945558899&realname=测试员&testBase64Str=[5rWL6K+V5a2X56ym5LiyMQ==,5rWL6K+V5a2X56ym5LiyMg==]testkey123testkey123testkey12345
16:56:50.061 [main] INFO com.example.utils.Signature - Sign Result:61867a7f32594eec1967fcddea8d96c3
(上传图片)签名字符串:61867a7f32594eec1967fcddea8d96c3
(上传图片)参数json={"idno":"465601200810081204","mobile":"19945558899","realname":"测试员","sign":"61867a7f32594eec1967fcddea8d96c3","testBase64Str":["5rWL6K+V5a2X56ym5LiyMQ==","5rWL6K+V5a2X56ym5LiyMg=="]} 16:56:50.089 [main] INFO com.example.utils.Signature - 签名前的map={testBase64Str=[5rWL6K+V5a2X56ym5LiyMQ==,5rWL6K+V5a2X56ym5LiyMg==], mobile=19945558899, sign=, class=, idno=465601200810081204, realname=测试员}
16:56:50.089 [main] INFO com.example.utils.Signature - Sign Before MD5:idno=465601200810081204&mobile=19945558899&realname=测试员&testBase64Str=[5rWL6K+V5a2X56ym5LiyMQ==,5rWL6K+V5a2X56ym5LiyMg==]testkey123testkey123testkey12345
16:56:50.089 [main] INFO com.example.utils.Signature - Sign Result:61867a7f32594eec1967fcddea8d96c3
16:56:50.089 [main] INFO com.example.utils.Signature - 签名后的字符串=61867a7f32594eec1967fcddea8d96c3
(上传图片)验证签名是否一致=true //非数组方法,弊端是:testBase64Str构建签名字符串的时候,默认取数组的第一个字符,而不是[]结构的全部数据。
16:59:15.692 [main] INFO com.example.utils.Signature - Sign Before MD5:idno=465601200810081204&mobile=19945558899&realname=测试员&testBase64Str=5rWL6K+V5a2X56ym5LiyMQ==testkey123testkey123testkey12345
16:59:15.697 [main] INFO com.example.utils.Signature - Sign Result:bfc9246143246f1852b4a29732aabcf6
(上传图片)签名字符串:bfc9246143246f1852b4a29732aabcf6
(上传图片)参数json={"idno":"465601200810081204","mobile":"19945558899","realname":"测试员","sign":"bfc9246143246f1852b4a29732aabcf6","testBase64Str":["5rWL6K+V5a2X56ym5LiyMQ==","5rWL6K+V5a2X56ym5LiyMg=="]} 16:59:15.775 [main] INFO com.example.utils.Signature - 签名前的map={testBase64Str=5rWL6K+V5a2X56ym5LiyMQ==, mobile=19945558899, sign=, class=, idno=465601200810081204, realname=测试员}
16:59:15.775 [main] INFO com.example.utils.Signature - Sign Before MD5:idno=465601200810081204&mobile=19945558899&realname=测试员&testBase64Str=5rWL6K+V5a2X56ym5LiyMQ==testkey123testkey123testkey12345
16:59:15.775 [main] INFO com.example.utils.Signature - Sign Result:bfc9246143246f1852b4a29732aabcf6
16:59:15.775 [main] INFO com.example.utils.Signature - 签名后的字符串=bfc9246143246f1852b4a29732aabcf6
(上传图片)验证签名是否一致=true

接口签名规则及Java代码demo实现的更多相关文章

  1. 微信支付接口--超详细带注释代码--Demo

    如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 如果对你有帮助的话麻烦点个[推荐]~最好还可以follow一下我的GitHub~感谢观看! 微 ...

  2. 四种java代码静态检查工具

    [转载]常用 Java 静态代码分析工具的分析与比较 转载自 开源中国社区 http://www.oschina.net/question/129540_23043       1月16日厦门 OSC ...

  3. API服务接口签名代码与设计,如果你的接口不走SSL的话?

    在看下面文章之前,我们先问几个问题 rest 服务为什么需要签名? 签名的几种方式? 我认为的比较方便的快捷的签名方式(如果有大神持不同意见,可以交流!)? 怎么实现验签过程 ? 开放式open ap ...

  4. [改善Java代码]在接口中不要存在实现代码

    第3章  类.对象及方法 书读得多而不思考,你会觉得自己知道的很多. 书读得多而思考,你会觉得自己不懂的越来越多. —伏尔泰 在面向对象编程(Object-Oriented Programming,O ...

  5. java接口签名(Signature)实现方案续

    一.前言 由于之前写过的一片文章 (java接口签名(Signature)实现方案 )收获了很多好评,此次来说一下另一种简单粗暴的签名方案.相对于之前的签名方案,对body.paramenter.pa ...

  6. java接口签名(Signature)实现方案

    预祝大家国庆节快乐,赶快迎接美丽而快乐的假期吧!!! 一.前言 在为第三方系统提供接口的时候,肯定要考虑接口数据的安全问题,比如数据是否被篡改,数据是否已经过时,数据是否可以重复提交等问题.其中我认为 ...

  7. 规则引擎集成接口(九)Java类对象

    Java类对象 右键点击“对象库” —“添加java类对象”,如下图: 弹出窗体,在文本框中输入类的全名“com.flagleader.test.Test”,选择该类型后确定,如下: 显示如下,勾选上 ...

  8. Java代码签名证书申请和使用指南

    第1步 下载签名工具 Step 1: Download Signing Tools 如果您还没有签名工具,请到SUN公司网站免费下载:http://java.sun.com/j2se/,推荐下载JDK ...

  9. 论坛源码推荐(11.6):iPhone6/6 plus屏幕适配Demo,Java代码转Objective-C

    http://www.cocoachina.com/ios/20141106/10153.html iPhone6/6 plus 屏幕适配Demo(代码底层处理)(论坛会员satian)htt 该项目 ...

  10. 接口测试-Java代码实现接口请求并封装

    前言:在接口测试和Java开发中对接口请求方法进行封装都非常有必要,无论是在我们接口测试的时候还是在开发自测,以及调用某些第三方接口时,都能为我们调用和调试接口提供便捷: Java实现对http请求的 ...

随机推荐

  1. Azkaban业务流程如何转化为DataWorks业务流程

    简介: 用户在迁移上云的时候,需要将云下的的Azkaban任务迁移上云,之前通过用户在DataWroks一步步创建对应的业务流程,其转化难度和转化时间都是一定的成本和时间,但如何能做到省时省力的方式迁 ...

  2. 深度 | 从DevOps到BizDevOps, 研发效能提升的系统方法

    ​简介:研发效能提升不知从何下手.一头雾水?阿里资深技术专家一文为你揭秘研发效能提升的系统方法. ​ 注:本文是对云栖大会何勉分享内容的整理 这几年"研发效能"一直是热词,很多组织 ...

  3. WPF 通过 RawInput 获取触摸消息

    触摸在 Windows 下属于比较特殊的输入,不同于键盘和鼠标,键盘和鼠标可以通过全局 Hook 的方式获取到鼠标和键盘的输入消息.而触摸则没有直接的 Hook 的方法.如果期望自己的应用,可以在没有 ...

  4. WPF 应用启动过程同时启动多个 UI 线程且访问 ContentPresenter 可能让多个 UI 线程互等

    在应用启动过程里,除了主 UI 线程之外,如果还多启动了新的 UI 线程,且此新的 UI 线程碰到 ContentPresenter 类型,那么将可能存在让新的 UI 线程和主 UI 线程互等.这是多 ...

  5. webpack调优技巧

    webpack优化主要有三个方面:1.提高构建速度,2.减少打包体积,3.优化用户体验 提高构建速度: 启用多线程 thread-loader 使用thread-loader插件可以启用多线程进行构建 ...

  6. MindSpore强化学习:使用PPO配合环境HalfCheetah-v2进行训练

    本文分享自华为云社区<MindSpore强化学习:使用PPO配合环境HalfCheetah-v2进行训练>,作者: irrational. 半猎豹(Half Cheetah)是一个基于Mu ...

  7. 【Python自动化】定时自动采集,并发送微信告警通知,全流程案例讲解!

    目录 一.概要 二.效果演示 三.代码讲解 3.1 爬虫采集行政处罚数据 3.2 存MySQL数据库 3.3 发送告警邮件&微信通知 3.4 定时机制 四.总结 一.概要 您好!我是@马哥py ...

  8. 13、web 中间件加固-Nginx 加固

    1.隐藏版本信息 避免被针对版本直接使用漏洞 修改 nginx.conf 文件 在 http 模块中添加信息:server_tokens off; 2.限制目录权限 某些目录为运维页面,不要公开访问 ...

  9. 【OpenVINO™】基于 C# 和 OpenVINO™ 部署 Blazeface 模型实现人脸检测

     前言 OpenVINO C# API 是一个 OpenVINO 的 .Net wrapper,应用最新的 OpenVINO 库开发,通过 OpenVINO C API 实现 .Net 对 OpenV ...

  10. golang map转xml

    package main import ( "encoding/xml" "fmt" ) type MyMap map[string]interface{} t ...