Spring Boot 项目自定义加解密实现配置文件的加密
在Spring Boot项目中, 可以结合Jasypt 快速实现对配置文件中的部分属性进行加密。 完整的介绍参照:
Spring Boot + Jasypt 实现application.yml 属性加密的快速示例
但是作为一个技术强迫症,总是想着从底层开始实现属性的加解密,以解答这背后机制的疑惑。
本篇在不使用Jasypt 的状况下,实现配置文件的加密,并且应用启动的时候自动解密加密属性以供系统使用。
1. 定义一个加解密的工具类
/*** Copyright (C) Oscar Chen(XM):* * Date: 2025-01-07* Author: XM*/package com.osxm.sb.encyproperties.util;import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;public class SecurityUtil {private static final String AES_GCM_NOPADDING = "AES/GCM/NoPadding";private static final int GCM_TAG_LENGTH = 128;private static final int GCM_IV_LENGTH = 12;public static SecretKey generateKeyByPassword(String password) throws Exception {// 使用SHA-256哈希函数MessageDigest sha = MessageDigest.getInstance("SHA-256");byte[] keyBytes = sha.digest(password.getBytes("UTF-8"));// AES-256需要一个长度为256位的密钥,所以取哈希的前32字节keyBytes = Arrays.copyOf(keyBytes, 32);// 创建密钥SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");return secretKey;}public static String encrypt(String data, String password) throws Exception {SecretKey key = generateKeyByPassword(password);return encrypt(data, key);}public static String encrypt(String data, SecretKey key) throws Exception {Cipher cipher = Cipher.getInstance(AES_GCM_NOPADDING);byte[] iv = new byte[GCM_IV_LENGTH];SecureRandom.getInstanceStrong().nextBytes(iv);GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);cipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec);byte[] encryptedData = cipher.doFinal(data.getBytes());byte[] encryptedDataWithIv = new byte[iv.length + encryptedData.length];System.arraycopy(iv, 0, encryptedDataWithIv, 0, iv.length);System.arraycopy(encryptedData, 0, encryptedDataWithIv, iv.length, encryptedData.length);return Base64.getEncoder().encodeToString(encryptedDataWithIv);}public static String decrypt(String data, String password) throws Exception {SecretKey key = generateKeyByPassword(password);return decrypt(data, key);}public static String decrypt(String encryptedDataWithIv, SecretKey key) throws Exception {byte[] decodedData = Base64.getDecoder().decode(encryptedDataWithIv);Cipher cipher = Cipher.getInstance(AES_GCM_NOPADDING);byte[] iv = new byte[GCM_IV_LENGTH];System.arraycopy(decodedData, 0, iv, 0, iv.length);GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);byte[] encryptedData = new byte[decodedData.length - iv.length];System.arraycopy(decodedData, iv.length, encryptedData, 0, encryptedData.length);byte[] decryptedData = cipher.doFinal(encryptedData);return new String(decryptedData);}
}
2. 定义一个继承EnumerablePropertySource的类: EncryptedPropertySource
EncryptedPropertySource
用于将数据库密码、API密钥等敏感配置信息以加密的形式存储。这样,即使配置文件(如.properties
文件或环境变量)被未经授权的人员访问,他们也无法直接获取到敏感的明文信息,因为信息已经被加密处理。
/*** Copyright (C) Oscar Chen(XM):* * Date: 2025-01-07* Author: XM*/
package com.osxm.sb.encyproperties.config;import java.util.HashMap;
import java.util.Map;import org.springframework.core.env.EnumerablePropertySource;import com.osxm.sb.encyproperties.util.SecurityUtil;public class EncryptedPropertySource extends EnumerablePropertySource<Map<String, Object>> {private final Map<String, Object> properties = new HashMap<>();public EncryptedPropertySource(String name, Map<String, Object> source) {super(name, source);source.forEach((key, value) -> {if (value != null) {try {properties.put(key, decrypt(value.toString()));} catch (Exception e) {properties.put(key, value);}}});}@Overridepublic String[] getPropertyNames() {return properties.keySet().toArray(new String[0]);}@Overridepublic Object getProperty(String name) {return properties.get(name);}private String decrypt(String encryptedValue) throws Exception {// 在这里实现你的解密逻辑// 例如,假设加密值是 "ENC(encryptedPassword)" 格式if (encryptedValue.startsWith("ENC(") && encryptedValue.endsWith(")")) {String encryptedPassword = encryptedValue.substring(4, encryptedValue.length() - 1);// 这里使用简单的Base64解码作为示例,你可以使用更复杂的解密算法return SecurityUtil.decrypt(encryptedPassword, "oscar");}return encryptedValue;}
}
3. 在启动类中添加初始化动作
在 Spring Boot 中,addInitializers
方法通常用于向ConfigurableApplicationContext
添加自定义的ApplicationContextInitializer
。ApplicationContextInitializer
是一个接口,允许你在ApplicationContext
刷新之前进行一些初始化工作。这在一些高级配置和启动时设置环境变量或属性时非常有用。
在Spring Boot中,environment
对象通常指的是Environment
接口的一个实例,它提供了访问应用程序属性源(PropertySource
)的方法。PropertySource
是一个抽象,它定义了如何访问一组属性(键值对)。
environment.getPropertySources().addFirst(...)
这行代码的作用是将一个新的PropertySource
实例添加到当前Environment
的属性源列表的最前面。这意味着当Spring Boot查找某个属性时,它会首先在这个新添加的PropertySource
中查找,如果找不到,才会继续在其他属性源中查找。
这种方法通常用于覆盖或添加额外的配置属性,特别是在需要确保某些属性具有最高优先级时。例如,你可能希望在应用程序启动时从外部源(如环境变量、命令行参数或加密的配置服务)加载配置,并确保这些配置覆盖任何默认或先前加载的配置。
这里的完整启动类代码如下:
@SpringBootApplication
public class EncypropertiesApplication {public static void main(String[] args) {SpringApplication application = new SpringApplication(EncypropertiesApplication.class);application.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment environment = applicationContext.getEnvironment();try (InputStream input = new ClassPathResource("application.yml").getInputStream()) {Yaml yaml = new Yaml();Map<String, Object> yamlProperties = yaml.load(input);Map<String, Object> flattenedProperties = new HashMap<>();flattenMap(yamlProperties, flattenedProperties, null);EncryptedPropertySource encryptedPropertySource = new EncryptedPropertySource("encryptedProperties",flattenedProperties);environment.getPropertySources().addFirst(encryptedPropertySource);} catch (IOException e) {e.printStackTrace();}}private void flattenMap(Map<String, Object> source, Map<String, Object> target, String path) {source.forEach((key, value) -> {String fullPath = (path == null ? key : path + "." + key);if (value instanceof Map) {flattenMap((Map<String, Object>) value, target, fullPath);} else {target.put(fullPath, value);}});}});application.run(args);}}
4. 验证
以上配置是否生效,可以通过Debug 模式调试加密字符串是否正常被解密。
完整的测试是在 application.yml 配置数据库的密码,整合起来验证是否能正确连接DB。
spring:application:name: encypropertiesdatasource:url: jdbc:mysql://localhost/osxmdbusername: rootpassword: ENC(gfsTDJv1lgAfp4q0XcrhMp3+ijj8T2Go/UPdYbPJPXa6PQ==)driver-class-name: com.mysql.cj.jdbc.Driver
本篇完整示例
- https://github.com/osxm/springbootency/tree/main/encyproperties
相关文章:
![](https://i-blog.csdnimg.cn/direct/5bff7c98516346619a277aafb9dd0fa3.png)
Spring Boot 项目自定义加解密实现配置文件的加密
在Spring Boot项目中, 可以结合Jasypt 快速实现对配置文件中的部分属性进行加密。 完整的介绍参照: Spring Boot Jasypt 实现application.yml 属性加密的快速示例 但是作为一个技术强迫症,总是想着从底层开始实现属性的加解密,…...
![](https://i-blog.csdnimg.cn/direct/2507617e04814969801452122fc2d22a.png)
在ubuntu下对NFS做性能测试
安装NFS 首先,安装服务 sudo apt update sudo apt install nfs-kernel-server然后创建共享文件夹 # 请自定义你自己的共享目录 sudo mkdir -p /exports/nfs4/homes sudo chmod -R 777 /exports/nfs4/homes# 这个可以根据no_root_squash标致选择设置。 # 如果不设…...
![](https://www.ngui.cc/images/no-images.jpg)
Spring-Cloud-Gateway-Samples,nacos为注册中心,负载均衡
背景:本想找个简单例子看下,无奈版本依赖太过复杂,花了点时间。记录下吧 使用Spring Cloud Gateway作为网关服务,Nacos作为注册中心,实现对子服务的负载均衡访问。简单例子。 一、gateway-main-nacos服务端ÿ…...
![](https://i-blog.csdnimg.cn/img_convert/c50eb7e1cc9b01c6d387f741a1f4087f.png)
StarRocks Awards 2024 年度贡献人物
在过去一年,StarRocks 在 Lakehouse 与 AI 等关键领域取得了显著进步,其卓越的产品功能极大地简化和提升了数据分析的效率,使得"One Data,All Analytics" 的愿景变得更加触手可及。 虽然实现这一目标的道路充满挑战且漫…...
Autoencoder(李宏毅)机器学习 2023 Spring HW8 (Boss Baseline)
1. Autoencoder 简介 Autoencoder是一种用于学习数据高效压缩表示的人工神经网络。它由两个主要部分组成: Encoder 编码器将输入数据映射到一个更小的、低维空间中的压缩表示,这个空间通常称为latent space或bottleneck。 这一过程可以看作是数据压缩,去除冗余信息,仅保留…...
![](https://www.ngui.cc/images/no-images.jpg)
深入探索 ScottPlot.WPF:在 Windows 桌面应用中绘制精美图表的利器
一、ScottPlot.WPF 简介 ScottPlot.WPF 是基于 ScottPlot 绘图库专门为 Windows Presentation Foundation (WPF) 框架量身定制的强大绘图组件。它无缝集成到 WPF 应用程序中,为开发者提供了一种简洁、高效的方式来可视化数据,无论是科学研究中的实验数据展示、金融领域的行情…...
![](https://www.ngui.cc/images/no-images.jpg)
React中的useMemo 和 useEffect 哪个先执行?
在 React 组件的渲染过程中,useMemo 和 useEffect 的执行顺序是不同的。具体来说: useMemo 先执行:useMemo 是在 渲染阶段 执行的,它的作用是缓存计算结果,确保在渲染过程中可以直接使用缓存的值。 useEffect 后执行&…...
![](https://i-blog.csdnimg.cn/direct/f107a4e81b2c47dcafaad567db85ed27.png#pic_center)
错误修改系列---基于RNN模型的心脏病预测(pytorch实现)
前言 前几天发布了pytorch实现,TensorFlow实现为:基于RNN模型的心脏病预测(tensorflow实现),但是一处繁琐地方 一处错误,这篇文章进行修改,修改效果还是好了不少;源文章为:基于RNN模型的心脏病…...
![](https://i-blog.csdnimg.cn/img_convert/974577131340fc756e4b48ac557c875f.jpeg)
Table-Augmented Generation(TAG):Text2SQL与RAG的升级与超越
当下AI与数据库的融合已成为推动数据管理和分析领域发展的重要力量。传统的数据库查询方式,如结构化查询语言(SQL),要求用户具备专业的数据库知识,这无疑限制了非专业人士对数据的访问和利用。为了打破这一壁垒&#x…...
![](https://www.ngui.cc/images/no-images.jpg)
Stable Diffusion本地部署教程(附安装包)
想使用Stable Diffusion需要的环境有哪些呢? python3.10.11(至少也得3.10.6以上):依赖python环境NVIDIA:GPUgit:从github上下载包(可选,由于我已提供安装包,你可以不用git)Stable Diffusion安装包工具包: NVIDIA:https://developer.nvidia.com/cuda-toolkit-archiv…...
![](https://i-blog.csdnimg.cn/direct/200af923c7fe47888ed27685a8e598a7.jpeg)
【物联网原理与运用】知识点总结(上)
目录 名词解释汇总 第一章 物联网概述 1.1物联网的基本概念及演进 1.2 物联网的内涵 1.3 物联网的特性——泛在性 1.4 物联网的基本特征与属性(五大功能域) 1.5 物联网的体系结构 1.6 物联网的关键技术 1.7 物联网的应用领域 第二章 感知与识别技术 2.1 …...
![](https://i-blog.csdnimg.cn/img_convert/004912d07814c27c009f041edd4283d2.webp?x-oss-process=image/format,png)
JuiceFS 2024:开源与商业并进,迈向 AI 原生时代
即将过去的 2024 年,是 JuiceFS 开源版本推出的第 4 年,企业版的第 8 个年头。回顾过去这一年,JuiceFS 社区版依旧保持着快速成长的势头,GitHub 星标突破 11.1K,各项使用指标增长均超过 100%,其中文件系统总…...
![](https://i-blog.csdnimg.cn/blog_migrate/415f4d65e495aff9ab45153a92afbc96.png)
C#,动态规划问题中基于单词搜索树(Trie Tree)的单词断句分词( Word Breaker)算法与源代码
1 分词 分词是自然语言处理的基础,分词准确度直接决定了后面的词性标注、句法分析、词向量以及文本分析的质量。英文语句使用空格将单词进行分隔,除了某些特定词,如how many,New York等外,大部分情况下不需要考虑分词…...
![](https://i-blog.csdnimg.cn/direct/a0c5424f13e54785ba6c00cbb420ac6a.png)
计算机网络(六)应用层
6.1、应用层概述 我们在浏览器的地址中输入某个网站的域名后,就可以访问该网站的内容,这个就是万维网WWW应用,其相关的应用层协议为超文本传送协议HTTP 用户在浏览器地址栏中输入的是“见名知意”的域名,而TCP/IP的网际层使用IP地…...
![](https://i-blog.csdnimg.cn/direct/57bc7936aad04d97994c915058aba699.png)
上海亚商投顾:沪指探底回升微涨 机器人概念股午后爆发
上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 一.市场情绪 市场全天探底回升,沪指盘中跌超1.6%,创业板指一度跌逾3%,午后集体拉升翻红…...
![](https://www.ngui.cc/images/no-images.jpg)
conda相关操作
conda 是一个开源的包管理和环境管理工具,主要用于 Python 和数据科学领域。它可以帮助用户安装、更新、删除和管理软件包,同时支持创建和管理虚拟环境。以下是关于 conda 的所有常见操作: 1. 安装 Conda Conda 通常通过安装 Anaconda 或 Mi…...
![](https://i-blog.csdnimg.cn/direct/0ecaf42659ef4102833be224134df830.png)
使用TCP协议实现智能聊天机器人
实验目的与要求 本实验是程序设计类实验,要求使用原始套接字编程,掌握TCP/IP协议与网络编程Sockets通信模型,并根据教师给定的任务要求,使用TCP协议实现智能聊天机器人。 (1)熟悉标准库socket 的用法。 …...
![](https://www.ngui.cc/images/no-images.jpg)
PHP二维数组去除重复值
Date: 2025.01.07 20:45:01 author: lijianzhan PHP二维数组内根据ID或者名称去除重复值 代码示例如下: // 假设 data数组如下 $data [[id > 1, name > Type A],[id > 2, name > Type B],[id > 1, name > Type A] // 重复项 ];// 去重方法 $dat…...
![](https://i-blog.csdnimg.cn/direct/c9a8601b771d45c5ba429ecfcc1ef1b1.png#pic_center)
2025年01月11日Github流行趋势
项目名称:xiaozhi-esp32 项目地址url:https://github.com/78/xiaozhi-esp32项目语言:C历史star数:2433今日star数:321项目维护者:78, MakerM0, whble, nooodles2023, Kevincoooool项目简介:构建…...
![](https://i-blog.csdnimg.cn/direct/7264c764f554465ea1fa600ea2c0ce3b.png)
备战蓝桥杯 队列和queue详解
目录 队列的概念 队列的静态实现 总代码 stl的queue 队列算法题 1.队列模板题 2.机器翻译 3.海港 双端队列 队列的概念 和栈一样,队列也是一种访问受限的线性表,它只能在表头位置删除,在表尾位置插入,队列是先进先出&…...
![](https://i-blog.csdnimg.cn/direct/cace272f4c234ed7888cb62bd86d227a.jpeg)
IT面试求职系列主题-Jenkins
想成功求职,必要的IT技能一样不能少,先说说Jenkins的必会知识吧。 1) 什么是Jenkins Jenkins 是一个用 Java 编写的开源持续集成工具。它跟踪版本控制系统,并在发生更改时启动和监视构建系统。 2)Maven、Ant和Jenkins有什么区别…...
![](https://i-blog.csdnimg.cn/direct/1321f81a45ad4a34a6505f8a305e0b5b.png)
Vue篇-06
1、路由简介 vue-rooter:是vue的一个插件库,专门用来实现SPA应用 1.1、对SPA应用的理解 1、单页 Web 应用(single page web application,SPA)。 2、整个应用只有一个完整的页面 index.html。 3、点击页面中的导航链…...
![](https://i-blog.csdnimg.cn/direct/a46f12e580824c8eae50d99e6b996a7f.png)
mysql binlog 日志分析查找
文章目录 前言一、分析 binlog 内容二、编写脚本结果总结 前言 高效快捷分析 mysql binlog 日志文件。 mysql binlog 文件很大 怎么快速通过关键字查找内容 一、分析 binlog 内容 通过 mysqlbinlog 命令可以看到 binlog 解析之后的大概样子 二、编写脚本 编写脚本 search_…...
![](https://www.ngui.cc/images/no-images.jpg)
ubuntu 配置OpenOCD与RT-RT-thread环境的记录
1.git clone git://git.code.sf.net/p/openocd/code openocd 配置gcc编译环境 2. sudo gedit /etc/apt/source.list #cdrom sudo apt-get install git sudo apt-get install libtool-bin sudo apt-get install pkg-config sudo apt-install libusb-1.0-0-dev sudo apt-get…...
![](https://i-blog.csdnimg.cn/direct/60de5bf9cf1d4a9caf03506b45a18863.png)
双系统解决开机提示security Policy Violation的方法
最近,Windows系统更新后,发现电脑开机无法进入桌面,显示“Verifiying shim SBAT data failed: security Policy Violation; So mething has gone seriously Wrong: SBAT self-check failed: Security Policy Violation”的英文错误信息。为了…...
![](https://www.ngui.cc/images/no-images.jpg)
附加共享数据库( ATTACH DATABASE)的使用场景
附加共享数据库(使用 ATTACH DATABASE)的功能非常实用,通常会在以下几种场景下需要用到: 1. 跨数据库查询和分析 场景: 你的公司有两个独立的数据库: 一个存储了学生信息 (school.db)一个存储了员工信息 …...
![](https://i-blog.csdnimg.cn/direct/9153a4f0249f498c98a99df91aabe1f9.jpeg#pic_center)
matlab的绘图的标题中(title)添加标量以及格式化输出
有时候我们需要在matlab绘制的图像的标题中添加一些变量,这样在修改某些参数后,标题会跟着一块儿变。可以采用如下的方法: x -10:0.1:10; %x轴的范围 mu 0; %均值 sigma 1; %标准差 y normpdf(x,mu,sigma); %使用normpdf函数生成高斯函数…...
![](https://i-blog.csdnimg.cn/img_convert/c58b2968a662e143c4b448dc2efcdd26.png)
2、第一个GO 程序
引言 接下里我们就用Go Land 工具,开发第一个GO程序。大家也可以用其他的开发工具,例如 Vs Code 1、新建项目 第一个是选择你的程序保存位置 (不要有中文)。 第二个是你的Go的编译器的安装地址。 选择完毕后,就点击 …...
![](https://i-blog.csdnimg.cn/direct/72610ea0be864826af7343e6413ff628.png)
【Linux-多线程】-线程安全单例模式+可重入vs线程安全+死锁等
一、线程安全的单例模式 什么是单例模式 单例模式是一种“经典的,常用的,常考的”设计模式 什么是设计模式 IT行业这么火,涌入的人很多.俗话说林子大了啥鸟都有。大佬和菜鸡们两极分化的越来越严重,为了让菜鸡们不太拖大佬的后…...
![](https://www.ngui.cc/images/no-images.jpg)
00000007_C语言设计模式
C语言设计模式 尽管 C 语言并不直接支持面向对象编程,但通过结构体和函数指针的灵活运用,我们依然可以实现多种经典的设计模式。 1. 工厂模式 1.1 工厂方法的定义与实现 工厂模式通过统一的接口创建对象,客户端无需知道具体的创建逻辑。 代…...
做招聘的网站有哪些内容/营销型网站定制
目录 1.树莓派刷机 2.树莓派登陆 2.1 HDMI 视频线连接到显示器 第1种 2.2 串口连接登陆 第2种 2.3 通过网络登陆树莓派 2.3.1 让树莓派入网 2.3.2 固定树莓派的ip地址 2.3.3 网络ssh方式登陆树莓派 第3种(最常用…...
![](/images/no-images.jpg)
公司网站维护费怎么做分录/网站优化推广是什么
第1关:方法1的准备工作:利用for语句创建列表 利用方括号、range函数可以创建列表,其实创建列表还有一种更强大、更方便的方法,就是使用 for 语句,这也是更简单绘制轨迹所采用的第 1 种方法,而本关任务就是学习它的使用方法。 #第1题 L = [101, 25, 38, 29, 108] ######…...
![](/images/no-images.jpg)
如何用织梦cms做网站/宁波网站快速优化
hover到卡片上的时候,卡片位移,向上移动6px: 1、现在原本布局就是卡片向上有个20的margin,所以hover的时候,直接改变margin-top值为14px,因为父元素的高度是用子元素撑开的,所以导致父元素的兄弟元素的位置也向上跑了&…...
![](https://s4.51cto.com/wyfs02/M02/86/BA/wKioL1fI2mjxmw6SAAANPpMXo04180.png)
好听的建筑公司名字大全/搜索引擎优化seo培训
安装PHPStudy2014,打开端口出现80端口 PID4 进程:System后来发现原来是我本地电脑安装了SQL SERVER 2008R2占用了端口,把它Reporting Services停止后就正常了:转载于:https://blog.51cto.com/myjieli/1845461...
怎么上传自己的做网站/seo助理
Java 导入 Java 导出 上传 前提准备2个Jar包: commons-fileupload-x.x.x.jar commons-io-x.x.x.jar 准备上传页面同步上传:<% page language"java" pageEncoding"UTF-8"%> <!DOCTYPE HTML> <html><head><…...
![](https://img-blog.csdnimg.cn/77e6ba836af44406bfbbf808c51c1db3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASm9obm55TGluMDA=,size_20,color_FFFFFF,t_70,g_se,x_16)
韶关网站建设墨子/注册公司流程和费用
Configuration注解 配置类 里面使用Bean标注在方法上,通过该方式给容器注册组件,以方法名作为组件的id(也可以通过Bean(“组件名”) 显示指定),返回类型就是组件类型,返回值就是组件在容器中的实例。默认也…...