最近在做项目的过程中,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 - 配置信息后处理的更多相关文章

  1. Redis篇之操作、lettuce客户端、Spring集成以及Spring Boot配置

    Redis篇之操作.lettuce客户端.Spring集成以及Spring Boot配置 目录 一.Redis简介 1.1 数据结构的操作 1.2 重要概念分析 二.Redis客户端 2.1 简介 2 ...

  2. Spring Boot 配置优先级顺序

    一般在一个项目中,总是会有好多个环境.比如: 开发环境 -> 测试环境 -> 预发布环境 -> 生产环境 每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一 ...

  3. spring boot配置springMVC拦截器

    spring boot通过配置springMVC拦截器 配置拦截器比较简单, spring boot配置拦截器, 重写preHandle方法. 1.配置拦截器: 2重写方法 这样就实现了拦截器. 其中 ...

  4. spring boot配置mybatis和事务管理

    spring boot配置mybatis和事务管理 一.spring boot与mybatis的配置 1.首先,spring boot 配置mybatis需要的全部依赖如下: <!-- Spri ...

  5. Spring Boot 配置元数据指南

    1. 概览 在编写 Spring Boot 应用程序时,将配置属性映射到 Java bean 上是非常有用的.但是,记录这些属性的最好方法是什么呢? 在本教程中,我们将探讨 Spring Boot C ...

  6. spring boot 配置虚拟静态资源文件

    我们实现的目的是:通过spring boot 配置静态资源访问的虚拟路径,可实现在服务器,或者在本地通过:http://ip地址:端口/资源路径/文件名  ,可直接访问文件 比如:我们本地电脑的:E: ...

  7. Spring Boot配置,读取配置文件

    Spring Boot配置,读取配置文件 一.配置Spring Boot 1.1 服务器配置 1.2 使用其他Web服务器 1.3 配置启动信息 1.4 配置浏览器显示ico 1.5 Yaml语法 1 ...

  8. Spring Boot -- 配置切换指南

    一般在一个项目中,总是会有好多个环境.比如: 开发环境 -> 测试环境 -> 预发布环境 -> 生产环境 每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一 ...

  9. spring boot 配置注入

    spring boot配置注入有变量方式和类方式(参见:<spring boot 自定义配置属性的各种方式>),变量中又要注意静态变量的注入(参见:spring boot 给静态变量注入值 ...

随机推荐

  1. 检查点--JMeter也有之二“检查点”

    检查点:简单的来理解一下,上一章讲到,我们对用户名和密码进行了参数化,那么怎样来判断jmeter有没有正确调用test.dat里面的文件呢.当然,我们可以从结果图表中查看.但我还是想在“登录”这个地方 ...

  2. Struts2笔记--文件下载

    Struts2提供了stream结果类型,该结果类型是专门用于支持文件下载功能的.配置stream类型的结果需要指定以下4个属性. contentType:指定被下载文件的文件类型 inputName ...

  3. 八. 输入输出(IO)操作6.文件与目录管理

    目录是管理文件的特殊机制,同类文件保存在同一个目录下不仅可以简化文件管理,而且还可以提高工作效率.Java 语言在 java.io 包中定义了一个 File 类专门用来管理磁盘文件和目录. 每个 Fi ...

  4. Parse error: syntax error, unexpected end of file in *.php on line * 解决方法

    Parse error: syntax error, unexpected end of file in *.php on line * 解决方法   这篇文章主要介绍了PHP错误Parse erro ...

  5. 6、Python模块

    最常用的两个模块: os    #可以允许python调用执行系统命令,如shell sys    #处理与python程序本身的事情   Python自带200多个常用模块 Python官网收集了2 ...

  6. JAVA之抽象类与抽象方法

    抽象方法:在类中没有方法体的方法,就是抽象方法.抽象类:含有抽象方法的类就叫抽象类.|||||||||抽象类不能被实例化(new)为什么要使用抽象方法?(以下是个人观点)因 为在面向对象的编程的思想中 ...

  7. 速查笔记(Linux Shell编程<下>)

    转载自: http://www.cnblogs.com/stephen-liu74/archive/2011/11/04/2228133.html 五.BASH SHELL编程: 1.    初始化顺 ...

  8. 20160208.CCPP体系具体解释(0018天)

    程序片段(01):main.c 内容概要:PointWithOutInit #include <stdio.h> #include <stdlib.h> //01.野指针具体解 ...

  9. 使用Spring开发和监控线程池服务

    第1步:添加maven 项目 第2步:添加依赖库 将Spring的依赖添加到Maven的pom.xml文件中. 1 2 3 4 5 6 7 8 9 10 11 <!-- Spring 3 dep ...

  10. [阿里Hao]Android无线开发的几种经常使用技术

    本文由阿里巴巴移动安全client.YunOS资深project师Hao(嵌入式企鹅圈原创团队成员)撰写,是Hao在嵌入式企鹅圈发表的第一篇原创文章.对Android无线开发的几种经常使用技术进行综述 ...