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 给静态变量注入值 ...
随机推荐
- #420 Div2 C
#420 Div2 C 题意 不断把数加入到一个栈里,取数的时候要求按照 1~n 的顺序取数,每次取数保证数一定在栈里,如果要取的数不在栈头,可以选择对栈排序一次.问最少排序几次. 分析 只要栈头的数 ...
- AppScan 浏览器兼容解决
手动探索的时候,因为打开的浏览器是appscan自带的,可能会存在兼容性问题,有些页面无法正常打开.那么是否可以用我们电脑上的浏览器(IE .火狐.谷歌)来进行录制 菜单栏--工具---选项----首 ...
- 洛谷——P1107 最大整数
P1107 最大整数 题目描述 设有n个正整数 (n<=20), 将它们连接成一排, 组成一个最大的多位整数. 例如: n=3时, 3个整数13, 312, 343连接成的最大整数为: 3433 ...
- POJ 2155 Matrix(树状数组+容斥原理)
[题目链接] http://poj.org/problem?id=2155 [题目大意] 要求维护两个操作,矩阵翻转和单点查询 [题解] 树状数组可以处理前缀和问题,前缀之间进行容斥即可得到答案. [ ...
- Unity3D的主要类图
原文:http://blog.teotigraphix.com/2011/05/17/unity3d-uml-gameobject-cheat-sheet/ 1. GameObject_Structu ...
- 初学Django:创建第一个项目+使用模板
1. 创建一个项目 之前在Anaconda 3里面用命令行安装了Django之后,有了可用的管理工具django-admin.py (1)用django.admin.py来创建一个项目Hellowor ...
- 链接服务器 "(null)" 的 OLE DB 访问接口 "SQLNCLI11" 指示该对象没有列,或当前用户没有访问该对象的权限。
原文:链接服务器 "(null)" 的 OLE DB 访问接口 "SQLNCLI11" 指示该对象没有列,或当前用户没有访问该对象的权限. SELECT * F ...
- mysql查询一个库中有多少张表
SELECT COUNT(*) TABLES, table_schema FROM information_schema.TABLES WHERE table_schema = 'palm_2_0_ ...
- Makefile学习之通配符和自动变量
规则中的通配符 “*” ,“?” ,“ [...]”, " % " , " wildcard " 1.“*” *.c表示所有后缀为.C的文件: 如果文件中用到 ...
- mongodb修改器(转)
MongoDB 修改器 对文档中的某些字段进行更新 $inc 专门用来增加(或减少)数字的,只能用于整数,长整数或双精度浮点型的值$inc键的值必须为数字,不能使用字符串,数组或其他非数字的值如果键不 ...