liuyulin
发布于 2024-02-02 / 78 阅读
0
0

Spring项目配置文件密码加密

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环境变量中添加一个新的配置,列表从后往前读取,在表头的配置会被保留,从而实现内容替换,其实两个配置都存在于表中。


评论