Spring Boot实现接口签名验证

项目场景:

        开放接口是指不需要登录凭证就允许被第三方系统调用的接口。为了防止开放接口被恶意调用,开放接口一般都需要验签才能被调用。

        在Spring Boot中实现接口校验签名通常是为了保证接口请求的安全性和数据的完整性。签名校验通常涉及对请求参数的签名计算和验证,以确保请求是由可信的发送方发送,并且在传输过程中没有被篡改。下面,我将详细介绍如何在Spring Boot应用中实现接口校验签名的过程。


解决方案:

1.配置签名密钥

签名密钥是用于生成和验证签名的秘密信息,生成规则自己定义,需要把生成的密钥提供给第三方。

比如:

appId:360aa3a3ba074da6a7bb17ae55e72d26
appSecret:81343DC5-6E80-483A-A427-E3DF5FA4E5F3

/*** 生成应用id和密钥*/
@RequestMapping(value = "/getSecret", method = RequestMethod.GET)
public Map<String, String> getSecret() {//生成应用id和密钥提供给第三方使用,具体生成规则自己定String appId = UUID.randomUUID().toString().replace("-", "").toLowerCase();String appSecret = UUID.randomUUID().toString().toUpperCase();System.out.println("appId:"+appId);System.out.println("appSecret:"+appSecret);Map<String, String> map = new HashMap<>();map.put("appId", appId);map.put("appSecret", appSecret);return map;
}

 2.定义签名算法

        一个用于生成签名,另一个用于验证签名。生成签名的方法通常将请求参数按照特定规则计算出一个签名值。常见的签名算法有HMAC-SHA1、HMAC-SHA256等。

        验证签名的方法则是对接收到的请求参数进行同样的处理,并计算出一个签名值,然后与请求中携带的签名值进行比对。

package com.test.utils;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class Signature {/*** 获取签名* @param secretKey 密钥* @param data  需要签名的数据* @return  签名*/public static String signWithHmacSha1(String secretKey, String data) {try {SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1");Mac mac = Mac.getInstance("HmacSHA1");mac.init(signingKey);return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8")));} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {e.printStackTrace();}return null;}/*** 验证签名* @param secretKey 密钥* @param data  需要签名的数据* @param hmac  已经签名的数据* @return  true:签名一致*/public static boolean verify(String secretKey, String data, String hmac) {String calculatedHmac = signWithHmacSha1(secretKey, data);return calculatedHmac.equals(hmac);}
}

3.拦截器或过滤器实现

使用Spring的拦截器(Interceptor)或过滤器(Filter)来实现对接口请求的签名校验。在拦截器或过滤器中,你可以获取到请求的参数,并调用签名验证方法来校验签名的有效性。

package com.test.aop;import com.test.utils.Signature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 签名拦截器*/
@Component
@Slf4j
public class SignInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");//分配的应用idString appId = request.getHeader("appId");//时间戳String timestampStr = request.getHeader("timestamp");//签名String signature = request.getHeader("signature");if(StringUtils.isBlank(appId) || StringUtils.isBlank(timestampStr) || StringUtils.isBlank(signature)){response.setStatus(500);response.getWriter().println("参数错误!");return false;}//这个密钥实际应该根据appId到数据库里查出来String appSecret = "81343DC5-6E80-483A-A427-E3DF5FA4E5F3";//如果密钥没查到
//        if(flag){
//            response.setStatus(500);
//            response.getWriter().println("密钥不存在!");
//        }//拼接数据String origin = appId + "\n" + appSecret + "\n" + timestampStr;if(!Signature.verify(appSecret, origin, signature)){response.setStatus(500);response.getWriter().println("签名错误!");return false;}//业务的时间戳long timestamp = Long.parseLong(timestampStr);//当前时间戳long currentTimestamp = System.currentTimeMillis() / 1000;//10分钟内有效long timeDifference = 10 * 60;if(Math.abs(timestamp - currentTimestamp) > timeDifference){response.setStatus(500);response.getWriter().println("签名过期!");return false;}//放行return true;}
}

配置拦截器

package com.test.config;import com.test.aop.SignInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;/*** WebMvc配置*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {@Resourceprivate SignInterceptor signInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//不拦截的地址List<String> excludedList = new ArrayList<>();//swagger地址excludedList.add("/swagger-ui.html");excludedList.add("/swagger-ui.html/**");excludedList.add("/webjars/**");excludedList.add("/swagger/**");excludedList.add("/doc.html");excludedList.add("/doc.html/**");excludedList.add("/swagger-resources/**");excludedList.add("/v2/**");excludedList.add("/favicon.ico");//生成应用id和密钥接口不拦截excludedList.add("/getSecret");registry.addInterceptor(signInterceptor).addPathPatterns("/**")//拦截所有请求.excludePathPatterns(excludedList);//排除的请求super.addInterceptors(registry);}
}

4.测试接口 

controller定义一个测试接口

/*** 测试签名*/
@RequestMapping(value = "/sign", method = RequestMethod.GET)
public String sign() {return "success";
}

模拟第三方调用: 

我们需要把接口请求头所需参数和签名的方法告知第三方。

 接口请求头参数如下:

参数名称中文参数值
appId应用id360aa3a3ba074da6a7bb17ae55e72d26
timestamp当前时间戳,精确到秒

1713838208

signature签名bjvXebFiHi2+I93BNs+8+Tl2I7k=

签名方法: 

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class Signature {/*** 获取签名* @param secretKey 密钥* @param data  需要签名的数据* @return  签名*/public static String signWithHmacSha1(String secretKey, String data) {try {SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1");Mac mac = Mac.getInstance("HmacSHA1");mac.init(signingKey);return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8")));} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {e.printStackTrace();}return null;}
}

 生成签名示例:

public static void main(String[] args) {//这里的应用id和密钥已实际分配的为准String appId = "360aa3a3ba074da6a7bb17ae55e72d26";String appSecret = "81343DC5-6E80-483A-A427-E3DF5FA4E5F3";//当前时间戳,精确到秒,示例:1713838208long timestamp = System.currentTimeMillis() / 1000;//拼接数据:appId、appSecret、timestampString origin = appId + "\n" + appSecret + "\n" + timestamp;String signature = Signature.signWithHmacSha1(appSecret, origin);//需要加到请求头的参数System.out.println("appId:"+appId);System.out.println("timestamp:"+timestamp);System.out.println("signature:"+signature);
}

 当第三方知道接口请求头所需参数和签名的方法后,就可以调用接口了

curl调用:

curl -X GET \http://localhost:8080/testservice/test/sign \-H 'appId: 360aa3a3ba074da6a7bb17ae55e72d26' \-H 'signature: bjvXebFiHi2+I93BNs+8+Tl2I7k=' \-H 'timestamp: 1713843128'

总结

  1. 这里签名由appId + "\n" + appSecret + "\n" + timestamp,生成签名字串
  2. 时间戳用于保证签名的有效性,即使签名被盗用,也只能在有效时间内使用
  3. appId、appSecret自己定义生成规则,保存到数据库中

源码:https://download.csdn.net/download/u011974797/89211980

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/4101.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

java如何使用webService方式调用对接第三方平台

实际使用记录&#xff0c;做个记录&#xff1a; 1、需要对方提供wsdl文件,该文件中有接口的Ip地址&#xff0c;方法名、参数等详细信息&#xff0c; wsdl文档中targetNamespace为命名空间 <xsd:element name"searchBGDMIInfo">标签中name是方法名&#xff1…

C语言考试程序题会用到的模板

// 质数判定 int isPrime(int x) {if(x < 2)return 0;for(int i 2;i < x / i;i)if(x % i 0)return 0;return 1; }// 最大公约数 int gcd(int a,int b) {return b 0 ? a : gcd(b,a%b); }// 最小公倍数 int lcm(int a,int b) {return a / gcd(a,b) * b; }// 分解因数 v…

数据结构-树和森林之间的转化

从树的二叉链表的定义可知&#xff0c;任何一棵和树对应的二叉树&#xff0c;其根节点的右子树必为空。这里我们举三个树&#xff0c;将这个由三个树组成的森林组成二叉树是这个样子的。 下面我们说明一下详细过程&#xff0c;首先将每个树转化为二叉的状态&#xff0c;如图所示…

NAT网络地址转换实验(华为)

思科设备参考&#xff1a;NAT网络地址转换实验&#xff08;思科&#xff09; 一&#xff0c;技术简介 NAT&#xff08;Network Address Translation&#xff09;&#xff0c;即网络地址转换技术&#xff0c;是一种在现代计算机网络中广泛应用的技术&#xff0c;主要用于有效管…

汇编语言(详解)

汇编语言安装指南 第一步&#xff1a;在github上下载汇编语言的安装包 网址&#xff1a;GitHub - HaiPenglai/bilibili_assembly: B站-汇编语言-pdf、代码、环境等资料B站-汇编语言-pdf、代码、环境等资料. Contribute to HaiPenglai/bilibili_assembly development by creat…

李廉洋:4.27黄金原油下周一行情分析及走势策略。

金价将出现六周来的首次单周下跌&#xff0c;因投资者在金价上涨数月后获利了结。自2月中旬的低点以来&#xff0c;金价已经上涨了约17%&#xff0c;尽管对美联储放松政策的预期正在减弱&#xff0c;但金价仍屡创新高。周五公布的最新通胀数据强化了高利率将暂时维持的观点。“…

MATLAB的几种边缘检测算子(Sobel、Prewitt、Laplacian)

MATLAB的几种边缘检测算子(Sobel、Prewitt、Laplacian) clc;close all;clear all;warning off;%清除变量 rand(seed, 100); randn(seed, 100); format long g;% 读取图像 image imread(lena.png); % 转换为灰度图像 gray_image rgb2gray(image); % 转换为double类型以进行计算…

Git泄露和hg泄露原理理解和题目实操

一.Git泄露 1.简介 Git是一个开源的分布式版本控制系统&#xff0c;它可以实现有效控制应用版本&#xff0c;但是在一旦在代码发布的时候&#xff0c;存在不规范的操作及配置&#xff0c;就很可能将源代码泄露出去。那么&#xff0c;一旦攻击者发现这个问题之后&#xff0c;就…

SQL Server 详细使用教程

SQL Server 详细使用教程 一、安装与启动 1. 安装 SQL Server 傻瓜式安装: 下载对应版本的 SQL Server 安装介质。运行安装程序&#xff0c;按照向导提示进行操作。选择合适的安装类型&#xff08;典型、自定义等&#xff09;&#xff0c;并配置实例名称、安装目录、服务账…

论文速览 | IEEE Symposium on Security and Privacy (SP), 2023 | FMCW雷达反射阵列欺骗攻击

注1:本文系"计算成像最新论文速览"系列之一,致力于简洁清晰地介绍、解读非视距成像领域最新的顶会/顶刊论文(包括但不限于 Nature/Science及其子刊; CVPR, ICCV, ECCV, SIGGRAPH, TPAMI; Light‑Science & Applications, Optica 等)。 本次介绍的论文是:<I…

MariaDB 修改用户密码的 SQL

有时候我们希望能够修改数据库中访问用户的密码。 但是我们只能 SQL 登录服务器后才能进行修改。 修改的 SQL 为&#xff1a; ALTER USER root% IDENTIFIED WITH mysql_native_password BY 123;针对实际上数据的配置情况&#xff0c;上面的 SQL 是需要进行一些调整的。 MySQ…

鸿蒙云函数调试坑点

如果你要本地调试请使用 const {payload, action} event.body/** 本地调试不需要序列化远程需要序列化 */ // const {payload, action} JSON.parse(event.body) const {payload, action} event.body 注意: 只要修改云函数&#xff0c;必须上传云函数 如果使用 const {pay…

前端HTML5学习1(新增布局,状态,列表,文本标签)

前端HTML5学习1&#xff08;新增布局&#xff0c;状态&#xff0c;列表&#xff0c;文本标签&#xff09; 新增布局标签新增状态标签新增列表标签新增文本标签 新增布局标签 HTML5 引入了许多新的语义化标签&#xff0c;用于更清晰地描述网页内容结构。这些新增的语义标签有助…

面试经典150题——整数转罗马数字

面试经典150题 day18 题目来源我的题解方法一 模拟方法二 不使用额外空间的方法 题目来源 力扣每日一题&#xff1b;题序&#xff1a;12 我的题解 方法一 模拟 俗称 狗屎代码 哈哈哈哈 时间复杂度&#xff1a;O(K)。K13 空间复杂度&#xff1a;O(1) public String intToRoma…

MATLAB初学者入门(21)—— 霍夫曼树

霍夫曼编码是一种广泛用于数据压缩的有效技术。它基于字符频率或概率来构造最优的前缀码&#xff0c;使得常用字符的编码长度较短&#xff0c;不常用的字符编码长度较长&#xff0c;从而达到压缩数据的目的。MATLAB中可以通过一系列步骤来实现霍夫曼树的构建和相应的编码过程。…

25计算机考研院校数据分析 | 南京大学

南京大学&#xff08;Nanjing University&#xff09;&#xff0c;简称“南大”&#xff0c;是中华人民共和国教育部直属、中央直管副部级建制的全国重点大学&#xff0c;国家首批“双一流”、“211工程”、“985工程”重点建设高校&#xff0c;入选首批“珠峰计划”、“111计划…

python实现DIY高考倒计时小软件

目录 一.前言 二.代码 三.分析 一.前言 高考是中国的全国性统一考试,全称为普通高等学校招生全国统一考试。它被认为是中国教育系统中最重要、最具决定性的考试之一。高考是中国学生从初中毕业后进入高中学习三年后的最终考试,也是他们升入大学的关键。 二.代码 import…

WordPress AI Engine 插件 文件上传致RCE漏洞复现(CVE-2023-51409)

0x01 产品简介 AI Engine插件是WordPress中的AI一体化解决方案,包括创建聊天机器人、生成内容和图像、推荐标题和帖子摘录、支持多种人工智能引擎等功能,可以节省用户时间。 0x02 漏洞概述 WordPress AI Engine 插件upload接口存在文件上传漏洞,未经身份验证的远程攻击者…

分布式复习提纲(ppt)

第一章 分布式系统定义&#xff1a;硬件控制数据基本属性必要属性主要特征 1-37目标 1-38 可访问性开放性可扩展性可用性可靠性透明性 1-43、 1-94 分布式支持技术 Ad hoc&#xff1a;IPC中间件 1-66、1-82 中间件要解决的问题 1-18 中间件的类别、特性 1-20RPC 安全性&#xf…