Spring Boot - 配置信息后处理
最近在做项目的过程中,PSS提出配置文件中类似数据库连接需要的用户名、密码等敏感信息需要加密处理(之前一直是明文的)。
为了快速完成任务,网上搜刮到jasypt包,也有相应的starter,使用方法可以参考blog
但是还是想具体弄清楚背后的实现。偶然看到Spring Boot中有个EnvironmentPostProcessor接口。看名字,它的实现类应该在配置文件加载完和Spring容器开始初始化之前起作用。这样的话,我们就可以实现该接口用来定制化配置信息,包括解密。
话不多说,show code,
@Component
public class DecryptAESConfigProcessor implements EnvironmentPostProcessor { private static short INDEX = 0;
private static String ITEM_FORMAT = "spring.config.decrypt-items[%d]";
private static Pattern PATTERN = Pattern.compile("AES\\((.+)\\)");
private static StringBuffer SB = new StringBuffer(); @Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
MutablePropertySources propertySources = environment.getPropertySources();
for (PropertySource propertySource: propertySources) {
if (propertySource instanceof OriginTrackedMapPropertySource){
INDEX = 0;
OriginTrackedMapPropertySource otmps = (OriginTrackedMapPropertySource)propertySource;
//System.out.println("property name = " + otmps.getName());
Map<String, Object> source = otmps.getSource();
String secretSalt = source.getOrDefault("spring.config.secret-salt", "").toString();
if (!"".equals(secretSalt)){
String salt = CommonUtil.decrypt(secretSalt, "sns");
while (INDEX > -1){
String item = String.format(ITEM_FORMAT, INDEX);
if (source.containsKey(item)){
String itemValue = source.get(item).toString();
String propertyValue = source.getOrDefault(itemValue, "").toString();
Matcher matcher = PATTERN.matcher(propertyValue);
boolean findAES = false;
while (matcher.find()){
//decrypt each AES()
findAES = true;
String decryptStr = CommonUtil.decrypt(matcher.group(1), salt);
matcher.appendReplacement(SB, decryptStr);
}
if (!findAES){
//decrypt entire item
source.put(itemValue, CommonUtil.decrypt(propertyValue, salt));
} else {
matcher.appendTail(SB);
source.put(itemValue, SB.toString());
}
SB.delete(0, SB.length());
INDEX++;
} else {
INDEX = -1;
}
}
}
}
} }
} 注意:需要将DecryptAESConfigProcessor声明到spring.factories中。 org.springframework.boot.env.EnvironmentPostProcessor=\
org.chris.springboot.config_encrypt.config.DecryptAESConfigProcessor
public class CommonUtil { private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
private static Cipher CIPHER;
private static KeyGenerator KEY_GENERATOR; static {
try {
CIPHER = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
KEY_GENERATOR = KeyGenerator.getInstance(KEY_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
} /**
* Decrypt by AES
* @param content
* @param salt
* @return
*/
public static String decrypt(String content, String salt) {
if (Objects.nonNull(content)) {
try {
byte[] decrypted = Base64.getDecoder().decode(content.getBytes("UTF-8"));
CIPHER.init(Cipher.DECRYPT_MODE, getSecretKey(salt));
return new String(CIPHER.doFinal(decrypted));
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
} /**
* Encrypt by AES
* @param content
* @param salt
* @return
*/
public static String encrypt(String content, String salt) {
if (Objects.nonNull(content)) {
try {
CIPHER.init(Cipher.ENCRYPT_MODE, getSecretKey(salt));
byte[] encrypted = CIPHER.doFinal(content.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
} /**
* Generate encrypted salt
* @param salt
* @return
*/
private static SecretKeySpec getSecretKey(final String salt) {
KEY_GENERATOR.init(128, new SecureRandom(salt.getBytes()));
SecretKey secretKey = KEY_GENERATOR.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
}
}
最后,配置文件中需要有类似以下配置项
解密规则如下,
1. 采用AES加密解密;
2. 在配置文件中
(1) 通过spring.config.decrypt-items指定需要解密的配置
(2) 通过spring.config.secret-salt指定AES的key(最好加密)
3. 如果需要解密的配置项中存在AES()模式的字符串,将会解密 () 中的内容,否则解密整个配置项
Spring Boot - 配置信息后处理的更多相关文章
- Redis篇之操作、lettuce客户端、Spring集成以及Spring Boot配置
Redis篇之操作.lettuce客户端.Spring集成以及Spring Boot配置 目录 一.Redis简介 1.1 数据结构的操作 1.2 重要概念分析 二.Redis客户端 2.1 简介 2 ...
- Spring Boot 配置优先级顺序
一般在一个项目中,总是会有好多个环境.比如: 开发环境 -> 测试环境 -> 预发布环境 -> 生产环境 每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一 ...
- spring boot配置springMVC拦截器
spring boot通过配置springMVC拦截器 配置拦截器比较简单, spring boot配置拦截器, 重写preHandle方法. 1.配置拦截器: 2重写方法 这样就实现了拦截器. 其中 ...
- spring boot配置mybatis和事务管理
spring boot配置mybatis和事务管理 一.spring boot与mybatis的配置 1.首先,spring boot 配置mybatis需要的全部依赖如下: <!-- Spri ...
- Spring Boot 配置元数据指南
1. 概览 在编写 Spring Boot 应用程序时,将配置属性映射到 Java bean 上是非常有用的.但是,记录这些属性的最好方法是什么呢? 在本教程中,我们将探讨 Spring Boot C ...
- spring boot 配置虚拟静态资源文件
我们实现的目的是:通过spring boot 配置静态资源访问的虚拟路径,可实现在服务器,或者在本地通过:http://ip地址:端口/资源路径/文件名 ,可直接访问文件 比如:我们本地电脑的:E: ...
- Spring Boot配置,读取配置文件
Spring Boot配置,读取配置文件 一.配置Spring Boot 1.1 服务器配置 1.2 使用其他Web服务器 1.3 配置启动信息 1.4 配置浏览器显示ico 1.5 Yaml语法 1 ...
- Spring Boot -- 配置切换指南
一般在一个项目中,总是会有好多个环境.比如: 开发环境 -> 测试环境 -> 预发布环境 -> 生产环境 每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一 ...
- spring boot 配置注入
spring boot配置注入有变量方式和类方式(参见:<spring boot 自定义配置属性的各种方式>),变量中又要注意静态变量的注入(参见:spring boot 给静态变量注入值 ...
随机推荐
- Java里如何判断一个String是空字符串或空格组成的字符串
要判读String是否为空字符串,比较简单,只要判断该String的length是否为0就可以,或者直接用方法isEmpty()来判断. 但很多时候我们也会把由一些不可见的字符组成的String也 ...
- viewport 测试以及总结
这里的总结的主要思想是ppk的文章(文末附有链接),加入了自己的总结,下面的测试用的是iphone5s,android是安卓5.5吋的手机,只是为了直观感受和方便解释拿了空出来的测试机给出的数据.详细 ...
- bzoj 5346: tree (其实是是某次雅礼集训的题)
用prufer序列的公式直接dp,O(n^4)的算法简简单单就写出来了23333. 按理说 O(n^4)是需要优化成O(n^3)才能过的,然鹅我也不知道我怎么过了23333 (那就懒得优化了hhhhh ...
- bzoj 2843: 极地旅行社
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1077 Solved: 645[Submit][Status][Discuss] Descripti ...
- delphi 浮点数转换成十六进制字符串的方法
我们在研究封包技术时,经常会碰到将浮点数转换成十六进制形式.比如在游戏中人物的座标,经常就用浮点数来表示.怎么将浮点数转换成十六进制字符串形式呢?下面我将写出其在DELPHI中的方法. 先 ...
- 咏南下拉列表非数据敏感控件--TYNSearch
咏南下拉列表非数据敏感控件--TYNSearch 拥有下拉列表控件可以大大地加速软件系统的开发. 控件适用于DELPHI5及以上版本的安装和使用. 控件的使用方法: procedure Tflog.s ...
- What is the purpose of mock objects?
Since you say you are new to unit testing and asked for mock objects in "layman's terms", ...
- Xcode 5 单元测试(二)OCMock和GHUnit
在Xcode 5 单元测试(一)使用XCTest进行单元测试中说了如何在Xcode 5中使用XCTest进行简单的单元测试,本文就来探讨下mock测试和更高级的工具GHUnit. Mock 首先科普下 ...
- 64位Ubuntu 14.04 安装wps
因为wps还没有提供64位版本号的wps,13.10開始又取消了ia32-libs的支持,经过自己測试,能够使用下面命令完毕安装 sudo dpkg -i 包名 sudo apt-get -f ins ...
- python2代码升级到python3工具
python模块lib2to3(py2转py3自动化工具) Usage: 2to3 [options] file|dir ... Options: -h, --help show this help ...