Spring项目配置文件密码加密
最近根据业务需求,需要给项目的配置文件中的密码加密。经过调研,有几种实现方式,包括使用开源的依赖,公司海星框架,自己实现。最终根据要求决定是自己实现。
Jasypt
Jasypt是一个开源的配置文件加密库,在配置文件中使用特定格式直接配置密文,启动应用的时候,Jasypt会自动将密码解密成明文供程序使用。
Spring boot 集成Jasypt
pom文件中引用
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>使用测试类加密密码
@Test
void test1() {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
// 设置密钥
encryptor.setPassword("liuyulin");
String en = encryptor.encrypt("Liuyl2000716.");
System.out.println(en);
String de = encryptor.decrypt(en);
System.out.println(de);
return;
}将加密后的密码写在配置文件中,需要使用ENC()包裹,将密文写在括号中
password: ENC(08SjdsIQf1DPUpsvmDYRL7qKF9SVXf2e9Pk5NA9n1wU=)这样,在项目启动的时候,jasypt会解密密码之后,覆盖原先的配置,使程序能够正常启动。
注意:密钥最好在jar包启动时,以命令的方式指定,否则密钥泄露,加不加密就没区别了
自己实现
其实就是实现配置文件中的内容替换,时间要在配置文件加载后,jdbc等启动前进行替换,这样项目才能正常启动。
实现可以有两种方式,一种是创建一个监听器,监听配置文件加载完成,对配置文件中的密文进行解密替换,另一种是创建一个类,覆写BeanFactoryPostProcessor,在bean加载后,对配置文件中内容进行替换。
ConfigPropertiesConvert
配置文件转换类
public class ConfigPropertiesConvert {
private static final String SPRING_DATASOURCE_PASSWORD = "spring.datasource.password";
public Properties propertiesConvert(ConfigurableEnvironment environment) {
Properties properties = new Properties();
properties = decryptPassword(properties,environment);
return properties;
}
private Properties decryptPassword(Properties properties, ConfigurableEnvironment environment) {
// db
String dbPassword = environment.getProperty(SPRING_DATASOURCE_PASSWORD);
String dbDecryptPassword = PasswordUtil.decodeByAES(dbPassword);
properties.put(SPRING_DATASOURCE_PASSWORD,dbDecryptPassword);
return properties;
}
}ApplicationListener
监听器实现配置文件覆盖
public class ApplicationListener implements SmartApplicationListener, Ordered {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return (ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) ||
ApplicationPreparedEvent.class.isAssignableFrom(eventType));
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
/* ApplicationEnvironmentPreparedEvent 是加载配置文件,初始化日志系统的事件。 */
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ConfigurableEnvironment environment = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment();
ConfigPropertiesConvert convert = new ConfigPropertiesConvert();
Properties properties = convert.propertiesConvert(environment);
environment.getPropertySources().addFirst(new PropertiesPropertySource("processorProperties", properties));
}
}
}使用监听器的方法,需要在启动类中添加监听器
application.addListeners(new ApplicationListener());MyBeanFactoryPostProcessor
继承BeanFactoryPostProcessor,bean加载后处理器,在bean加载完成后进行配置文件替换
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware, Ordered {
private ConfigurableEnvironment environment;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ConfigPropertiesConvert configPropertiesConvert = new ConfigPropertiesConvert();
Properties properties = configPropertiesConvert.propertiesConvert(environment);
environment.getPropertySources().addFirst(new PropertiesPropertySource("processorProperties", properties));
}
@Override
public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment) environment;
}
@Override
public int getOrder() {
return 0;
}
}其实,对配置文件的覆盖并不是直接替换,是在ConfigurableEnvironment环境变量中添加一个新的配置,列表从后往前读取,在表头的配置会被保留,从而实现内容替换,其实两个配置都存在于表中。