接口签名规则及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. 参与 Apache 顶级开源项目的 N 种方式,Apache Dubbo Samples SIG 成立!

    简介: 一说到参与开源项目贡献,一般大家的反应都是代码级别的贡献,总觉得我的代码被社区合并了,我才算一个贡献者,这是一个常见的错误认知.其实,在一个开源社区中有非常多的角色是 non-code con ...

  2. Jaeger插件开发及背后的思考

    ​简介: 本文主要介绍Jaeger最新的插件化后端的接口以及开发方法,让大家能够一步步的根据文章完成一个Jaeger插件的开发.此外SLS也推出了对于Jaeger的支持,欢迎大家试用. 随着云原生 + ...

  3. JavaScript 如何实现一个响应式系统

    JavaScript 如何实现一个响应式系统 第一阶段目标 数据变化重新运行依赖数据的过程 第一阶段问题 如何知道数据发生了变化 如何知道哪些过程依赖了哪些数据 第一阶段问题的解决方案 我们可用参考现 ...

  4. dotnet 如何将 Microsoft.Maui.Graphics 对接到 UNO 框架

    本文将和大家介绍如何将 Microsoft.Maui.Graphics 对接到 UNO 框架里面.一旦完成 Microsoft.Maui.Graphics 对接,即可让 UNO 框架复用现有的许多绘制 ...

  5. WPF 使用 VideoDrawing 播放视频

    本文告诉大家如何在 WPF 使用 VideoDrawing 进行视频播放 用这个方法有什么优势?其实只是想作为某个控件的背景,某个控件的背景使用视频而已 控件的背景使用 DrawingBrush 传入 ...

  6. 迁移 dotnet 6 提示必须将目标平台设置为 Windows 平台

    我在迁移一个古老的项目为 .NET 6 框架,但是 VS 提示 error NETSDK1136 如果使用 Windows 窗体或 WPF,或者引用使用 Windows 窗体或 WPF 的项目或包,则 ...

  7. 2019-9-27-微软的-P2P-下载方式

    title author date CreateTime categories 微软的 P2P 下载方式 lindexi 2019-09-27 09:44:44 +0800 2019-09-27 09 ...

  8. Docker镜像基本原理

    前言 Docker系列文章: 如果没有安装过Docker请参考本文最后部分,大家从现在开始一定要按照我做的Demo都手敲一遍,印象会更加深刻的,加油! 为什么学习Docker Docker基本概念 什 ...

  9. 【AI新趋势期刊#2】AI发明计算机算法,如何给大模型排行,照片秒变二维码,视频一键动漫风

    前言 每天都要浏览大量AI相关新闻,是不是感到信息量爆炸,有效信息少? 这么多新产品和新工具,到底哪些是真正是有价值的,哪些只是浮躁的一时热点? 想参与AI产品和工具的开发,从哪里能够获得大量的灵感和 ...

  10. Fast Möbius Transform 学习笔记 | FMT

    小 Tips:在计算机语言中 \(\cap\) = & / and, \(\cup\) = | / or First. 定义 定义长度为 \(2^n\) 的序列的 and 卷积 \(A = B ...