springboot 自定义配置文件加密规则

时间:2022-08-08
本文章向大家介绍springboot 自定义配置文件加密规则,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一般情况下,我们做项目的时候,中间件例如mysql,redis, zk 的账号密码一般都是写在配置文件里面的, 这样代码泄露的情况下, 就很不安全。

由第三方的加密的工具 jasypt 这种jar包。 这里我们仿写它来实现自己的配置文件加密规则。

jasypt 连接:https://github.com/ulisesbocchio/jasypt-spring-boot

具体的使用大家看我发的地址。

这里我们要用到ConfigurableEnviroment 这个类,我们来看一下源码

public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
    void setActiveProfiles(String... var1);

    void addActiveProfile(String var1);

    void setDefaultProfiles(String... var1);

   // resource 文件多个,这个可以是classpath ,file ,default 的
    MutablePropertySources getPropertySources();
   // 获取系统配置文件
    Map<String, Object> getSystemProperties();
   // 获取系统环境变量
    Map<String, Object> getSystemEnvironment();

    void merge(ConfigurableEnvironment var1);
}

首先我们要自己写一个类实现BeanFactoryPostProcessor ,和order 接口

public class PropertiesEncryptionConfig implements BeanFactoryPostProcessor, Ordered {

    // 前缀的key 
    public static final String PREFIX_PROPERTY = "xxxxx.encrypt.prefix";
    // 后缀的key 
    public static final String SUFFIX_PROPERTY = "xxxxx.encrypt.suffix";

    // 私钥的key 
    public static final String RSA_PRIVATE_KEY_PROPERTY = "xxxxx.encrypt.privateKey";

    // 前缀默认值
    public static final String DEFAULT_PREFIX = "xxxxx[";

     //后缀默认值
    public static final String DEFAULT_SUFFIX = "]";


    private static final Logger LOG = LoggerFactory.getLogger(PropertiesEncryptionConfig.class);

    // 在通过@bean 注入进来
    public   ConfigurableEnvironment  environment ;

    public PropertiesEncryptionConfig(ConfigurableEnvironment environment) {
        this.environment = environment;
    }

    private String prefix;

    private String suffix;

    private String privateKey;


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        MutablePropertySources propertySources = environment.getPropertySources();
        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource instanceof OriginTrackedMapPropertySource) {
                // 只有这个才是加载properties 文件的,getsource 返回的就是map
                OriginTrackedMapPropertySource om = (OriginTrackedMapPropertySource) propertySource;
                Map<String, Object> source = om.getSource();
                source.forEach((k, v) -> {
                    String property = environment.getProperty(k);
                    if (hasPreAndSuf(property)) {
                        LOG.info("开始处理 k = [{}]", k);
                        try {
                            String relay = splitPreAndSuf(property, this.prefix, this.suffix);
                            // 这里获取去掉前缀后缀的值 在通过自己的解密规则 ,
                            //这里 AesUtils 可以搞成注入模式, 这样使用的时候可以进行加密。自己写aes 的加密工具类 
                            String decrypt = AesUtils.aesDecrypt(relay, getPrivateKey(environment));
                            source.put(k, decrypt);
                        }
                        catch (Exception e) {
                            LOG.error("配置文件加密异常错误信息: ", e);
                        }
                    }
                });
            }
        }
    }

    private String getPrivateKey(ConfigurableEnvironment environment) throws Exception {
        // 支持从系统环境变量 java -jar 运行的时候获取
        this.privateKey = System.getProperty(RSA_PRIVATE_KEY_PROPERTY, "");
        if (StringUtils.hasText(this.privateKey)) {
            return this.privateKey;
        }
        // 支持从文件获取
        this.privateKey = environment.getProperty(RSA_PRIVATE_KEY_PROPERTY);
        if (StringUtils.hasText(this.privateKey)) {
            return this.privateKey;
        }
        // 都没有就会报错
        throw new Exception(" properties aes  private key is null!");
    }

    // 判断一下,前缀后缀是否匹配
    private boolean hasPreAndSuf(String property) {
        return property.startsWith(getPrefix(environment)) && property.endsWith(getSuffix(environment));
    }

    // 去掉前缀后缀获取中间值
    protected String splitPreAndSuf(String str, String prefix, String suffix) {
        return str.replace(prefix, "").replace(suffix, "");
    }

    // 获取后缀,没有使用默认值
    private String getSuffix(ConfigurableEnvironment environment) {
        this.suffix = environment.getProperty(SUFFIX_PROPERTY);
        if (StringUtils.hasLength(suffix)) {
            return this.suffix;
        }
        this.suffix = DEFAULT_SUFFIX;
        return DEFAULT_SUFFIX;
    }

   // 获取前缀,使用默认值 
    private String getPrefix(ConfigurableEnvironment environment) {
        this.prefix = environment.getProperty(PREFIX_PROPERTY);
        if (StringUtils.hasLength(prefix)) {
            return this.prefix;
        }
        this.prefix = DEFAULT_PREFIX;
        return DEFAULT_PREFIX;
    }

    /**
     *  提高优先级
     * @return
     */
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE -100;
    }
}
@Configuration
public class EnablePropertiesEncryption {

    @Bean
    public PropertiesEncryptionConfig getPropertiesEncryption(ConfigurableEnvironment configurableEnvironment){
        return  new PropertiesEncryptionConfig(configurableEnvironment);
    }
    
    // 加密解密工具类 ,可以在spring单元测试使用@Autowired注入
    @Bean
    public AesUtils getAes(){
        return  new AesUtils();
    }
}

这样我们就基本实现了jasypt 的功能。