对SpringBoot配置文件配置项加密原理

参考认识BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor - 知乎

SpringBoot 之 Jasypt 实现yml配置文件加密_-djasypt.encryptor.password-CSDN博客

【springboot】jasypt加密_jasypt.encryptor.password-CSDN博客

实现:

导包:

使用说明参考GitHub - ulisesbocchio/jasypt-spring-boot: Jasypt integration for Spring boot

        <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>

生成加密后的配置value:

public class EncryptionUtil {

    //https://blog.csdn.net/qq_41055045/article/details/126740841
    public static void main(String[] args) {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        // 加密方式
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        // 盐值
        config.setPassword("salt");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        // 加密明文
        String encryptValue1 = encryptor.encrypt("root");
        String encryptValue2 = encryptor.encrypt("root");

        System.out.println(encryptValue1);
        System.out.println(encryptValue2);
        // 解密密文
        String decryptValue = encryptor.decrypt("1B94SNKIuVmRNKeNmd2dkvAJTCilDPlof8l/FroMMYrH/nxXDf1OPdlUYkbBXB48");
        System.out.println(decryptValue);

    }

}

配置文件片段:

spring:
  datasource:
    primary:
      jdbc-url: jdbc:postgresql://localhost:5432/test?characterEncoding=utf8&useSSL=true
      username: postgres
      password: ENC(76va5Nw3V+NjHHPh0Ekei7hwitxCAYCzEIpoJLYMOebc+VbCm66hYWm12+AWoKcO) #root
      type: com.alibaba.druid.pool.DruidDataSource
    hikari:
      driver-class-name: org.postgresql.Driver
    secondary:
      jdbc-url: jdbc:sqlserver://localhost:1433;DatabaseName=test;Trusted_Connection=True
      username: sa
      password: ENC(H0MxJHbEiwXXiRp09UwEbU91HcNiufhAUTeIrptzW5vLllycbWodE0BgIxtDAoU7) #root
      type: com.alibaba.druid.pool.DruidDataSource
      hikari:
        driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
#参考
#https://zhuanlan.zhihu.com/p/653695574
#https://blog.csdn.net/qq_41617261/article/details/121448939
jasypt:
  encryptor:
    password: ${ENCRYPT:salt}

原理:

主要思路是实现了BeanFactoryPostProcessor,再装饰容器中原来的PropertySource类。   

参考认识BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor - 知乎 

BeanFactoryPostProcessor位于org.springframework.beans.factory.config包中。它与BeanPostProcessor有相似的核心逻辑,但它们之间的主要区别在于它们所操作的对象。BeanFactoryPostProcessor的主要目的是对Bean的配置元数据进行操作,这意味着它可以影响Bean的初始配置数据。

在Spring IoC容器实例化beans之前,特别是除了BeanFactoryPostProcessor之外的其他beans,BeanFactoryPostProcessor有权利修改这些beans的配置。在Spring中,所有的beans在被完全实例化之前都是以BeanDefinition的形式存在的。BeanFactoryPostProcessor为我们提供了一个机会,使我们能够在bean完全实例化之前调整和修改这些BeanDefinition。对BeanDefinition的任何修改都会影响后续的bean实例化和初始化过程。

 源码解析:

package com.ulisesbocchio.jasyptspringboot.configuration;

import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyResolver;
import com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

/**
 * <p>{@link BeanFactoryPostProcessor} that wraps all {@link PropertySource} defined in the {@link Environment}
 * with {@link com.ulisesbocchio.jasyptspringboot.wrapper.EncryptablePropertySourceWrapper} and defines a default {@link
 * EncryptablePropertyResolver} for decrypting properties
 * that can be configured through the same properties it wraps.</p>
 * <p>
 * <p>It takes the lowest precedence so it does not interfere with Spring Boot's own post processors</p>
 *
 * @author Ulises Bocchio
 */
@Slf4j
public class EnableEncryptablePropertiesBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {

    private final ConfigurableEnvironment environment;
    private final EncryptablePropertySourceConverter converter;

    public EnableEncryptablePropertiesBeanFactoryPostProcessor(ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
        this.environment = environment;
        this.converter = converter;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("Post-processing PropertySource instances");
        MutablePropertySources propSources = environment.getPropertySources();//得到原始配置类,再做替换
        converter.convertPropertySources(propSources);
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 100;
    }
}

com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter#makeEncryptable 

方法内部得到PropertySource包装类 EncryptableMapPropertySourceWrapper内部封装了CachingDelegateEncryptablePropertySource,CachingDelegateEncryptablePropertySource内部封装了EncryptablePropertyResolver

    public <T> PropertySource<T> makeEncryptable(PropertySource<T> propertySource) {
        if (propertySource instanceof EncryptablePropertySource || skipPropertySourceClasses.stream().anyMatch(skipClass -> skipClass.equals(propertySource.getClass()))) {
            if (!(propertySource instanceof EncryptablePropertySource)) {
                log.info("Skipping PropertySource {} [{}", propertySource.getName(), propertySource.getClass());
            }
            return propertySource;
        }
        PropertySource<T> encryptablePropertySource = convertPropertySource(propertySource);
        log.info("Converting PropertySource {} [{}] to {}", propertySource.getName(), propertySource.getClass().getName(),
                AopUtils.isAopProxy(encryptablePropertySource) ? "AOP Proxy" : encryptablePropertySource.getClass().getSimpleName());
        return encryptablePropertySource;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值