【SpringBootStarter】自定义全局加解密组件
【SpringBootStarter】
目的
- 了解
SpringBoot Starter
相关概念以及开发流程 - 实现自定义
SpringBoot Starter
(全局加解密) - 了解测试流程
- 优化
最终引用的效果:
<dependency><groupId>com.xbhog</groupId><artifactId>globalValidation-spring-boot-starter</artifactId><version>1.0.0</version>
</dependency>
【开源地址】https://gitee.com/xbhog/encry-adecry-spring-boot-starter;欢迎star
了解SpringBoot Starter相关概念以及开发流程
SpringBoot Starter
SpringBoot Starter
作用将一组相关的依赖打包,简化项目的配置和初始化过程,通过特定的Starter
开发者可以快速的实现特定功能模块的开发和扩展。
自定义Starter
能够促进团队内部资源的复用,保持项目间的一致性,提升协作效率并且有助于构建稳定、高效的大型系统。
开发流程
注入SpringBoot的方式
在刚开始开发Starter
的时候,首先考虑的是怎么能注入到SpringBoot中
?
这部分涉及到部分SpringBoot
的自动装配原理,不太清楚的朋友可以补习下;
注入SpringBoot
需要配置文件,在项目中的resources
资源目录中创建该目录和文件。
demo-spring-boot-starter
└── src└── main└── java└── com.xbhog├── DemoBean.java└── DemoBeanConfig.java└── resources└── META-INF└── spring.factories
在spring.factories
中我们指定一下自动装配的配置类,格式如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xbhog.DemoBeanConfig
/*** @author xbhog* @describe:*/
@Slf4j
@Configuration
public class DemoBeanConfig {@Beanpublic DemoBean getDemo() {log.info("已经触发了配置类,正在初始化DemoBean...");return new DemoBean();}
}
@Slf4j
public class DemoBean {public void getDemo(){log.info("方法调用成功");}
}
这样就可以将设置的包扫描路径下的相关操作打包到SpringBoot
中。
SpringBoot
主类启动器:初始化的操作,感兴趣的朋友可以研究下
完成后,我们可以打包该项目,然后在测试工程红进行Maven的引入、测试。
测试
新建Spring
测试工程,引入依赖:
<dependency><groupId>com.xbhog</groupId><artifactId>demo-spring-boot-starter</artifactId><version>1.0</version>
</dependency>
@RestController
public class BasicController implements ApplicationContextAware {private ApplicationContext applicationContext;/**两种引入方式都可以@Autowiredprivate DemoBean demoBean;*/@GetMapping("/configTest")public void configTest() {DemoBean demoBean = applicationContext.getBean(DemoBean.class);demoBean.getDemo();}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
请求地址后,可以观察控制台,如下日志表示SpringBoot Starter
可以使用了。
到此,一个简单的Starter
开发完成了,后续可以围绕工程,根据需求和业务,对通用功能(接口操作日志、异常、加解密、白名单等)进行封装,最后打到Maven
仓库中进行使用。
自定义SpringBoot Starter(全局加解密)
来源
在之前金融系统开发中,需要对接多个第三方的服务且数据安全性要求比较高;在接口评审阶段需要双方在数据传输的时候进行接口加解密;起初在第一个服务对接的时候,将相关的加解密操作写到工具类中;随着后续服务的增多,代码的侵入越来越严重。
封装
选择通过Starter
进行功能的封装;好处:引用方便,开发迭代方便,团队复用度高且对业务没有侵入。
开发
思路:通过配置文件初始化,让配置类注解@ComponentScan
扫描到的Bean等
注入到SpringBoot
中,通过自定义注解和``RequestBodyAdvice/ResponseBodyAdvice组合拦截请求,在
BeforBodyRead/beforeBodyWrite`中进行数据的前置处理,解密后映射到接口接收的字段或对象。
接口上的操作有两种方式:
- 注解+
AOP
实现 - 注解+
RequestBodyAdvice/ResponseBodyAdvice
这里我选择的第二种的RequestBodyAdvice/ResponseBodyAdvice
,抛砖引玉一下。
**【注】**第二种存在的局限性是:只能针对POST
请求中的Body
数据处理,无法针对GET
请求进行处理。
项目结构:
encryAdecry-spring-boot-starter
└── src└── main└── java└── com.xbhog├── advice│ ├──ResponseBodyEncryptAdvice.java│ └──RequestBodyDecryptAdvice.java├── annotation│ └──SecuritySupport├── handler│ ├──impl│ │ └──SecurityHandlerImpl.java│ └──SecurityHandler└── holder│ ├──ContextHolder.java│ ├──EncryAdecryHolder.java│ └──SpringContextHolder.java└──GlobalConfig.java└── resources└── META-INF└── spring.factories
项目处理流程图:
核心代码:
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {log.info("进入【RequestBodyDecryptAdvice】beforeBodyRead的操作,方法:{}",parameter.getMethod());SecuritySupport securitySupport = parameter.getMethodAnnotation(SecuritySupport.class);assert securitySupport != null;ContextHolder.setCryptHolder(securitySupport.securityHandler());String original = IOUtils.toString(inputMessage.getBody(), Charset.defaultCharset());//todolog.info("该流水已插入当前请求流水表");String handler = securitySupport.securityHandler();String plainText = original;if(StringUtils.isNotBlank(handler)){SecurityHandler securityHandler = SpringContextHolder.getBean(handler, SecurityHandler.class);plainText = securityHandler.decrypt(original);}return new MappingJacksonInputMessage(IOUtils.toInputStream(plainText, Charset.defaultCharset()), inputMessage.getHeaders());
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {log.info("进入【ResponseBodyEncryptAdvice】beforeBodyWrite的操作,方法:{}",returnType.getMethod());String cryptHandler = ContextHolder.getCryptHandler();SecurityHandler securityHandler = SpringContextHolder.getBean(cryptHandler, SecurityHandler.class);assert body != null;return securityHandler.encrypt(body.toString());
}
该Starter
中的全局加解密默认采用的国密非对称加密SM2
,在开发过程中遇到了该问题InvalidCipherTextException: invalid cipher text
【原因】 私钥和公钥值不是成对存在的,每次调用SmUtil.sm2()
会生成不同的随机密钥对。
【解决】在该Starter
中采用@PostConstruct
修饰方法,在项目运行中只会初始化运行一次该方法,保证了SmUtil.sm2()
只会调用一次,不会生成不同的随机秘钥对。
【ISSUES#1890
】详细请看该地址:https://hub.fgit.cf/dromara/hutool/issues/1890
/*** @author xbhog* @date 2024/02/01 13:23**/
@Slf4j
@Component
public class EncryAdecryHolder {public static SM2 sm2 = null;@PostConstructpublic void encryHolder(){KeyPair pair = SecureUtil.generateKeyPair("SM2");byte[] privateKey = pair.getPrivate().getEncoded();byte[] publicKey = pair.getPublic().getEncoded();log.info("生成的公钥:{}",publicKey);log.info("生成的私钥:{}",privateKey);sm2= SmUtil.sm2(privateKey, publicKey);}
}
除了默认的加密方式,还可以通过SecurityHandler
接口进行扩展,扩展出来的impl
可以在@SecuritySupport(securityHandler="xxxxxx")
中指定。
/*** @author xbhog* @describe: 全局加解密注解* @date 2023/6/8*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SecuritySupport {/*securityHandlerImpl*/String securityHandler() default "securityHandlerImpl";String exceptionResponse() default "";}
测试
复用之前的测试项目,引用打包的mavne
依赖:
<dependency><groupId>com.xbhog</groupId><artifactId>encryAdecry-spring-boot-starter</artifactId><version>1.0.0</version>
</dependency>
启动项目,初始化公私钥。
测试接口代码如下:
@Slf4j
@RestController
public class BasicController implements ApplicationContextAware {@Resource(name = "demoSecurityHandlerImpl")private SecurityHandler encryAdecry;private ApplicationContext applicationContext;// http://127.0.0.1:8080/hello?name=lisi//@SecuritySupport(securityHandler = "demoSecurityHandlerImpl")@SecuritySupport@PostMapping("/hello")public String hello(@RequestBody String name) {return "Hello " + name;}@GetMapping("/configTest")public String configTest(@RequestParam("name") String name) {/*DemoBean demoBean = applicationContext.getBean(DemoBean.class);demoBean.getDemo();*/return encryAdecry.encrypt(name);//return MD5.create().digestHex16(name);}
}
优化
优化后的项目结构:
encryAdecry-spring-boot-starter
└── src└── main└── java└── com.xbhog├── advice│ ├──ResponseBodyEncryptAdvice.java│ └──RequestBodyDecryptAdvice.java├── annotation│ └──SecuritySupport├── handler│ ├──impl│ │ └──EncryAdecryImpl.java│ └──SecurityHandler└── holder│ ├──ContextHolder.java│ └──SpringContextHolder.java├──GlobalProperties.java└──GlobalConfig.java└── resources└── META-INF└── spring.factories
增加配置类,用于绑定外部配置(properties
和YAML
)到Java对象的的一种机制;
@Data
@ConfigurationProperties(GlobalProperties.PREFIX)
public class GlobalProperties {/*** 默认前缀*/public static final String PREFIX = "encryption.type";/*** 加解密算法*/private String algorithmType;/*** 加解密key值*/private String key;
}
注解修改:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SecuritySupport {/*** 项目默认加解密实现类encryAdecryImpl* */String securityHandler() default "encryAdecryImpl";}
重写Starter
默认的加解密方式:
@Slf4j
@Component
public class EncryAdecryImpl implements SecurityHandler {@Resourceprivate GlobalProperties globalProperties;private static volatile SM2 sm2;@Overridepublic String encrypt(String original) {log.info("【starter】具体加密的数据{}",original);return sm2.encryptBase64(original, KeyType.PublicKey);}@Overridepublic String decrypt(String original) {String decryptData = StrUtil.utf8Str(sm2.decryptStr(original, KeyType.PrivateKey));log.info("【starter】具体解密的数据:{}",decryptData);return decryptData;}@PostConstruct@Overridepublic void init() {log.info("======>获取映射的加密算法类型:{}",globalProperties.getAlgorithmType());//传的是加密算法KeyPair pair = SecureUtil.generateKeyPair(globalProperties.getAlgorithmType());byte[] privateKey = pair.getPrivate().getEncoded();byte[] publicKey = pair.getPublic().getEncoded();sm2= SmUtil.sm2(privateKey, publicKey);}
}
相关文章:

【SpringBootStarter】自定义全局加解密组件
【SpringBootStarter】 目的 了解SpringBoot Starter相关概念以及开发流程实现自定义SpringBoot Starter(全局加解密)了解测试流程优化 最终引用的效果: <dependency><groupId>com.xbhog</groupId><artifactId>globalValidation-spring…...

【射影几何15】python双曲几何工具geometry_tools
目录 一、说明二、环境问题:如何安装三、实现一个简单的例子四、绘制双曲组五、使用有限状态自动机加快速度六、资源和代码 一、说明 Geometry_tools 是一个 Python 包,旨在帮助您处理和可视化双曲空间和射影空间上的群动作。 该包主要构建在 numpy、…...
机器人抓取 [ 题目/摘要 ] 更新中..
题目:Robotic Grasping of Novel Objects using Visionl 链接:机器人抓取新物体 | IEEE Xplore(IEEE的Xplore) 【端到端】 摘要:我们考虑抓取新物体的问题,特别是第一次通过视觉看到的物体。抓取以前未知的…...

【51单片机】外部中断和定时器中断
目录 中断系统中断介绍中断概念 中断结构及相关寄存器中断结构中断相关寄存器 外部中断实验外部中断配置软件设计实验现象 定时器中断定时器介绍51 单片机定时器原理51 单片机定时/计数器结构51 单片机定时/计数器的工作方式 定时器配置硬件设计软件设计实验现象 中断系统 本章…...

零售行业供应商数据分发,怎样提高安全性和效率?
零售行业是我国经济发展的重要组成,零售行业包罗万象,如包括汽车零售、日化零售、快消品零售等,不同细分行业的运营模式各不相同,但大体来说,零售行业都具备最基础的供应商和零售商,供应商将商品或服务卖给…...

Windows下Node.js下载安装及环境变量配置教程
Windows下Node.js下载安装及环境变量配置教程 安装版本:node-v18.19.0-x64.msi 文章目录 Windows下Node.js下载安装及环境变量配置教程一、Node.js和NPM简介二、下载地址三、安装步骤四、环境配置五、安装淘宝镜像总结 一、Node.js和NPM简介 1、Node.js …...
广义表-C语言
广义表(Generalized List)是一种扩展了线性表的数据结构,它在线性表的基础上增加了元素可以是表的特点。在广义表中,元素不仅可以是单个的数据元素,还可以是一个子表,而子表中的元素也可以是数据元素或其他…...

uniapp+uView 【详解】录音,自制音频播放器
效果预览 代码实现 <template><view class"btnListBox"><view class"audioBox" v-if"audioLength"><u-row><u-col span"2"><u--text aligncenter :text"currentTime"></u--text>…...

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)
1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据(例如训练样本)对感兴趣的未知变量(例如类别标 记)进行估计和推测。概率模型(probabilistic model)提供了一种描述框架,将描述任…...
cool 框架 node 后端封装三方Api post请求函数
1.需求 现在一些数据源 ,需要从三方地址拿到一些数据 比如说电影列表 信息了 影院列表信息了 等一些展示的数据,但是人家这种东西 害需要使用 appkey appserect 这种验签 这种需求 你前端调用接口是直接调用不了的 因为需要用到验签 需要后端接口转接一…...

awd总结
总结: 由于是第一次参加AWD比赛,各方面经验都不足,在参赛的前几天也是疯狂搜集各种脚本、框架、工具等,同时也参考b站的视频进行学习,我发现就是还是实操才能更快的学习 我觉得就是我前期的准备工作不足,…...
【react】react+es6+antd5.13.2+ts,antd表格的操作如何在父组件写?
reactes6antd5.13.2ts,antd表格的操作如何在父组件写? 我的子组件columns.tsx,只加表头,操作放在父组件。 columns.tsx的代码: export const dataColumns [{title: 项目成员,dataIndex: name,key: name,},{title: 可选账号,alig…...
virtio笔记
最近在看虚拟化相关的东西,以virtio-console为例,记录下。 此文只是学习笔记,文中肯定有不少错误,不要参考 devicemd侧: virtio_console.c中,初始化会对port->cb赋值为 viritio_console_control_tx&am…...

初始web服务器(并基于idea来实现无需下载的tomcat)
前言 前面学习了对应的http协议,我们知道了他是在网络层进行数据传输的协议,负责相应数据以及接收数据的规则,但是在人员开发后端的时候不仅仅需要你写io流进行数据传输,还需要你进行对应的tcp协议来进行数据打包发送http协议-CSD…...

软件文档测试
1 文档测试的范围 软件产品由可运行的程序、数据和文档组成。文档是软件的一个重要组成部分。 在软件的整人生命周期中,会用到许多文档,在各个阶段中以文档作为前阶段工作成果的体现和后阶段工作的依据。 软件文档的分类结构图如下图所示: …...

从零开始手写mmo游戏从框架到爆炸(七)— 消息封装
导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客 上一篇,我们初步把消息handler 注册到了服务中,在进行后续工作之前我们需要再做一些准备工作。 第一:把之前自己管理的bean放到spring中…...
从Unity到Three.js(画线组件line)
JavaScript 0基础,只是照着官方文档临摹了下,之后有时间再进行细节学习和功能封装。 import * as THREE from three; //引入threejsconst renderer new THREE.WebGLRenderer();//创建渲染器 //设置渲染范围,当前撑满全屏,屏幕左上角是&…...
LCP 30. 魔塔游戏 - 力扣(LeetCode)
题目描述 小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减…...

数据结构——单向链表和双向链表的实现(C语言版)
目录 前言 1. 链表 1.1 链表的概念及结构 1.2 链表的分类 2. 单链表接口实现 2.1 数据结构设计与接口函数声明 2.2 创建结点,打印,查找 2.3 尾插,头插,尾删,头删 2.4 插入或删除 2.4.1在指定位置后 2.4.2在…...
TCP和UDP相关问题(重点)(4)——4.使用TCP的协议有哪些?使用UDP的协议有哪些?
4.使用TCP的协议有哪些?使用UDP的协议有哪些? 使用TCP的协议有:HTTP3.0之前的HTTP协议、HTTPS、FTP、SMTP、SSH... 使用UDP的协议有:HTTP3.0、DNS、DHCP......
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...