当前位置: 首页 > news >正文

java 过滤器 接口(API)验证入参,验签(sign) Demo

java 过滤器 接口(API)验证入参,验签(sign) Demo

一、思路
1、配置yml文件;
2、创建加载配置文件类;
3、继承 OncePerRequestFilter 重写方法 doFilterInternal;
4、注册自定义过滤器;


二、步骤

1、配置yml文件;
###系统签名验证配置
biw:
  ###过滤器开关是否打开
  enable: true
  ###过滤器-验签秘钥(自定义一个字符串)
  securityKey: ccf12f15155c9c564daf1783a6f65f69a4a0
  ###过滤器-URL
  urlPathPatterns: /test/test001/*,/com/baidu006/*

2、创建加载配置文件类;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @Author * @create 2023/07/18*/
@Data
@Component
@ConfigurationProperties(prefix = "biw")
public class BiwConfig {/*** 系统通讯密钥*/private String securityKey;/*** 签名验证URL路径*/private String urlPathPatterns;/*** 是否开启签名验证*/private Boolean enable;}

3、继承 OncePerRequestFilter 重写方法 doFilterInternal;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.test.baidu.ResultCodeEnum;
import com.test.baidu.config.BiwConfig;
import com.test.baidu.common.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;/*** BIW系统接口鉴权过滤器** @Author * @Date 2023/07/18*/
@Slf4j
@Component
public class BiwSignFilter extends OncePerRequestFilter {@Autowiredprivate BiwConfig biwConfig;private final String SIGN_FIELD_NAME = "sign";private final String KEY_FIELD_NAME = "key";/*** doFilterInternal** @param request* @param response* @param filterChain* @throws ServletException* @throws IOException*/@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {try {ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);// 判断签名验证开关是否开启if (!biwConfig.getEnable()) {filterChain.doFilter(requestWrapper, response);return;}String bodyText = this.readHttpBody(requestWrapper);log.info("[系统接口鉴权]body内容: {}", bodyText);JSONObject jsonBody = JSONObject.parseObject(bodyText);Object signRequest = jsonBody.get(SIGN_FIELD_NAME);if (biwConfig.getEnable() && null == signRequest) {log.error("签名信息不存在");this.doReturn(response, Result.createError(ResultCodeEnum.SIGN_NOT_EXISTS.getCode(), ResultCodeEnum.SIGN_NOT_EXISTS.getMessage()));return;}String sign = this.signMD5(jsonBody);// 验证签名if (biwConfig.getEnable() && !sign.equals(signRequest)) {log.error("签名验证失败, 签名计算值 {} 签名请求值{} body内容{}", sign, signRequest, bodyText);this.doReturn(response, Result.createError(ResultCodeEnum.SIGN_ERROR.getCode(), ResultCodeEnum.SIGN_ERROR.getMessage()));return;}filterChain.doFilter(requestWrapper, response);} catch (Exception e) {log.error("签名验证异常", e);this.doReturn(response, Result.create500Error(e.getMessage()));return;}}/*** readHttpBody** @param requestWrapper* @return* @throws IOException*/private String readHttpBody(ServletRequest requestWrapper) throws IOException {BufferedReader reader = new BufferedReader(new InputStreamReader(requestWrapper.getInputStream(), Charset.forName("UTF-8")));String line = "";StringBuilder sb = new StringBuilder();while ((line = reader.readLine()) != null) {sb.append(line);}return sb.toString();}/*** doReturn** @param response* @param result* @throws IOException*/private void doReturn(HttpServletResponse response, Result result) throws IOException {ServletOutputStream out = response.getOutputStream();out.write(JSON.toJSONString(result).getBytes());out.flush();}/*** signMD5 : MD5签名加密** @param jsonObject* @return*/public String signMD5(JSONObject jsonObject) {Iterator it = jsonObject.getInnerMap().keySet().iterator();Map<String, Object> map = new TreeMap<String, Object>();StringBuilder signSb = new StringBuilder();while (it.hasNext()) {Object key = it.next();Object value = jsonObject.get(key);if (SIGN_FIELD_NAME.equals(key)) {continue;}map.put(key.toString(), value);}for (Map.Entry<String, Object> entry : map.entrySet()) {signSb.append(entry.getKey());signSb.append("=");signSb.append(entry.getValue());signSb.append("&");}signSb.append(KEY_FIELD_NAME).append("=").append(biwConfig.getSecurityKey());String sign = DigestUtils.md5Hex(signSb.toString()).toUpperCase();return sign;}/*** 生成签名*/public static void main(String[] args) {String json = "{\"endTime\":\"2023-07-01 08:00:00\",\"startTime\":\"2023-07-01 00:00:00\",\"pageNum\":1,\"pageSize\":50,\"requestId\":\"test001\"}";JSONObject jsonObject = JSON.parseObject(json);Iterator it = jsonObject.getInnerMap().keySet().iterator();Map<String, Object> map = new TreeMap<String, Object>();StringBuilder signSb = new StringBuilder();while (it.hasNext()) {Object key = it.next();Object value = jsonObject.get(key);if ("sign".equals(key)) {continue;}map.put(key.toString(), value);}for (Map.Entry<String, Object> entry : map.entrySet()) {signSb.append(entry.getKey());signSb.append("=");signSb.append(entry.getValue());signSb.append("&");}signSb.append("key").append("=").append("ccf12f15155c9c564daf1783a6f65f69a4a0");String sign = DigestUtils.md5Hex(signSb.toString()).toUpperCase();System.out.println(sign);}}

4、注册自定义过滤器;

import com.test.baidu.config.BiwConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author * @date 2023/07/18* @description: 系统过滤配置*/
@Configuration
public class BiwFilterConfig {@Autowiredprivate BiwSignFilter biwSignFilter;@Autowiredprivate BiwConfig biwConfig;/*** biwBillPullFilterConfig* 数据-签名过滤** @return*/@Beanpublic FilterRegistrationBean<BiwSignFilter> biwBillPullFilterConfig() {FilterRegistrationBean<BiwSignFilter> registration = new FilterRegistrationBean<>();// 注册自定义过滤器registration.setFilter(biwSignFilter);// 过滤所有路径// registration.addUrlPatterns(biwConfig.getUrlPathPatterns().split(","));registration.addUrlPatterns(biwConfig.getUrlPathPatterns());// 过滤器名称registration.setName("biwParametersFilter");// 优先级,越低越优先registration.setOrder(1);return registration;}}

5、每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中

解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题

import org.apache.commons.io.IOUtils;import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;/*** @Author * @create 2023/07/18*/
public class RequestWrapper extends HttpServletRequestWrapper {private byte[] requestBody;private HttpServletRequest request;public RequestWrapper(HttpServletRequest request) throws IOException {super(request);this.request = request;}@Overridepublic ServletInputStream getInputStream() throws IOException {/*** 每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中* 解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题*/if (null == this.requestBody) {ByteArrayOutputStream baos = new ByteArrayOutputStream();IOUtils.copy(request.getInputStream(), baos);this.requestBody = baos.toByteArray();}final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener listener) {}@Overridepublic int read() {return bais.read();}};}public byte[] getRequestBody() {return requestBody;}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(this.getInputStream()));}
}

相关文章:

java 过滤器 接口(API)验证入参,验签(sign) Demo

java 过滤器 接口&#xff08;API&#xff09;验证入参&#xff0c;验签&#xff08;sign&#xff09; Demo 一、思路 1、配置yml文件; 2、创建加载配置文件类; 3、继承 OncePerRequestFilter 重写方法 doFilterInternal; 4、注册自定义过滤器; 二、步骤 1、配置yml文件; ###系…...

独家!微信正在灰测一款全新消金产品

来源 | 镭射财经&#xff08;leishecaijing&#xff09; 「镭射财经」独家获悉&#xff0c;微信将推出一款名为“微信分期”的新消费信贷产品&#xff0c;目前该产品正处于小范围灰测阶段&#xff0c;还未正式上线。上线后&#xff0c;微信将运营微信分付和微信分期两款自营消…...

阿秀C++笔记-学习记录

81.C中的组合和继承相比的优缺点 在C中组合一对象系用描述对象包对象系组一个拥对象例其变合类的含的现。这的量类当有员被创建。 以下一个示例&#xff0c;展示了在C中如何实现组合关系&#xff1a; class Engine {// Engine class definition... };class Car {Engine engi…...

前端入门到入土?

文章目录 前言http和https的区别&#xff0c;https加密的原理是&#xff1f;区别https的加密原理 TCP为什么要三次握手&#xff1f;proxy代理的原理&#xff1f;内存泄漏&#xff1f;什么是内存泄漏&#xff1f;为什么会有内存泄漏&#xff1f;内存泄漏的情况&#xff1f;如何防…...

架构设计基础设施保障IaaS之网络

目录 1 DNS运用1.1 DNS功能作用1.2 DNS配置实践 2 DNS生产最佳实践方案2.1 全球加速功能2.2 不同运营商的加速方案2.3 全球业务高可用方案2.4 跨地域负载均衡 3 DNS域名劫持解决方案4 CDN剖析4.1 CDN原理4.2 缓存过期配置处理流程4.3 缓存配置规则 5 CDN运用6 CDN最佳实践方案6…...

zabbix安装部署

前期准备&#xff1a;安装mysql数据库和nginx 一、下载zabbix rpm -Uvh https://repo.zabbix.com/zabbix/4.4/rhel/7/x86_64/zabbix-release-4.4-1.el7.noarch.rpm yum-config-manager --enable rhel-7-server-optional-rpms yum install epel-release numactl yum install…...

零碎的C++

构造函数和析构函数 构造函数不能是虚函数&#xff0c;而析构函数可以是虚函数。原因如下&#xff1a; 构造函数不能是虚函数&#xff0c;因为在执行构造函数时&#xff0c;对象还没有完全创建&#xff0c;还没有分配内存空间&#xff0c;也没有初始化虚函数表指针。如果构造…...

模糊测试面面观 | 模糊测试是如何发现异常情况的?

协议模糊测试是一种用于评估通信协议、文件格式和API实现系统安全性和稳定性的关键技术。在模糊测试过程中&#xff0c;监视器扮演着关键角色&#xff0c;它们能够捕获异常情况、错误响应、资源利用等&#xff0c;为测试人员提供有价值的信息&#xff0c;有助于发现潜在漏洞和问…...

C#备份数据库文件

c#备份数据库文件完整代码 sqlServer 存储过程&#xff1a; USE [PSIDBase] GO /****** Object: StoredProcedure [dbo].[sp_BackupDB] Script Date: 2023/8/31 16:49:02 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GOALTER procedure [dbo].[sp_BackupDB]…...

行军遇到各种复杂地形怎么处理?

行军遇到各种复杂地形怎么处理&#xff1f; 【安志强趣讲《孙子兵法》第30讲】 【原文】 凡军好高而恶下&#xff0c;贵阳而贱阴&#xff0c;养生而处实&#xff0c;军无百疾&#xff0c;是谓必胜。 【注释】 阳&#xff0c;太阳能照到的地方。阴&#xff0c;太阳照不到的地方。…...

Python Number(数字).............................................

Python Number 数据类型用于存储数值。 数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值&#xff0c;将重新分配内存空间。 以下实例在变量赋值时 Number 对象将被创建&#xff1a; var1 1 var2 10您也可以使用del语句删除一些 Number 对象引用。 del语句…...

设置 Hue Server 与 Hue Web 界面之间的会话超时时间

设置 Hue Server 与 Hue Web 界面之间的会话超时时间 在 CDH 的 Hue 中&#xff0c;Auto Logout Timeout 参数表示用户在不活动一段时间后将自动注销&#xff08;登出&#xff09;的超时时间。当用户在 Hue 中处于不活动状态超过该设定时间时&#xff0c;系统将自动注销用户&am…...

openGauss学习笔记-57 openGauss 高级特性-并行查询

文章目录 openGauss学习笔记-57 openGauss 高级特性-并行查询57.1 适用场景与限制57.2 资源对SMP性能的影响57.3 其他因素对SMP性能的影响57.4 配置步骤 openGauss学习笔记-57 openGauss 高级特性-并行查询 openGauss的SMP并行技术是一种利用计算机多核CPU架构来实现多线程并行…...

软考(1)-面向对象的概念

目录 一. 软考基本信息 1. 软考时间&#xff1a; 2. 软考科目&#xff1a; 3.专业知识介绍 -- 综合知识考点分布 4. 专业介绍 -- 软件设计考点分布 二. 面向对象概念 1. 封装 考点一&#xff1a;对象 考点二&#xff1a;封装private 2. 继承 考点三&#xff1a;类 考…...

深度学习推荐系统(四)WideDeep模型及其在Criteo数据集上的应用

深度学习推荐系统(四)Wide&Deep模型及其在Criteo数据集上的应用 在2016年&#xff0c; 随着微软的Deep Crossing&#xff0c; 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出&#xff0c; 推荐系统全面进入了深度学习时代&#xff0c; 时至今日&#x…...

第十二章 YOLO的部署实战篇(中篇)

cuda教程目录 第一章 指针篇 第二章 CUDA原理篇 第三章 CUDA编译器环境配置篇 第四章 kernel函数基础篇 第五章 kernel索引(index)篇 第六章 kenel矩阵计算实战篇 第七章 kenel实战强化篇 第八章 CUDA内存应用与性能优化篇 第九章 CUDA原子(atomic)实战篇 第十章 CUDA流(strea…...

面试题查漏补缺 i++和 ++ i哪个效率更高

i 和 i 哪个效率更高&#xff1f; 在这里声明&#xff0c;简单地比较前缀自增运算符和后缀自增运算符的效率是片面的&#xff0c;因为存在很多因素影响这个问题的答案。首先考虑内建数据类型的情况:如果自增运算表达式的结果没有被使用&#xff0c;而是仅仅简单地用于增加一员…...

Docker的数据管理(持久化存储)

文章目录 一、概述二、数据卷三、数据卷容器四、端口映射五、容器互联&#xff08;使用centos镜像&#xff09;总结 一、概述 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&a…...

定时脚本自动自动将文件push到git

写脚本 绝对路径 环境注意 写python&#xff0c;bash脚本执行调用 py程序 定制crontab -e 日志要指定输入文件中 项目地址 https://gitee.com/stdev_1/sshpi10/ bash脚本 #!/bin/bash 设置要监控的仓库路径 #path~/github/ #watch_dir“/home/pi/gittest/ipset/sshpi10” p…...

025: vue父子组件中传递方法控制:$emit,$refs,$parent,$children

第025个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...