最近在搭建微服务框架封装基础工具包的时候用到了很多有关spring boot配置文件相关的知识,今天讲一下我在研究spring boot 配置文件属性加密解密过程中的收获。

相关文档查看进行思路构建

通过spring boot 官方文档查询到了:
Customize the Environment or ApplicationContext Before It Starts 在启动环境或ApplicationContext之前定制它
在这里插入图片描述 一个SpringApplication 拥有用于对上下文或环境应用自定义的ApplicationListeners 和ApplicationContextInitializers。
Spring boot引导会从META-INF/ Spring .factories中加载大量这样的定制,以供内部使用。
这里有多种注册其他自定义的方法:

  • 编程的方式,通过在SpringApplication 启动之前调用addListeners addInitializers方法进行注册。
  • 声明式,通过设置context.initializer.classes or context.listener.classes的配置。
  • 声明式,通过添加一个META-INF/spring.factories文件 ,打包成jar让应用程序当作库调用。
    SpringApplication 发送一个事件ApplicationEvents去监听(在上下文创建之前),然后为ApplicationContext发布的事件注册侦听器。
    还可以通过EnvironmentPostProcessor在刷新应用程序上下文之前定制Environment
    每个实现都应该注册到文件
    META-INF/spring.factories
    中,如下示例:
    org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
    

该实例可以加载任意模块并且添加到Environment,例如,下面的示例从类路径加载一个YAML配置文件:

  public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {

    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Resource path = new ClassPathResource("com/example/myapp/config.yml");
        PropertySource<?> propertySource = loadYaml(path);
        environment.getPropertySources().addLast(propertySource);
    }

    private PropertySource<?> loadYaml(Resource path) {
        if (!path.exists()) {
            throw new IllegalArgumentException("Resource " + path + " does not exist");
        }
        try {
            return this.loader.load("custom-resource", path).get(0);
        }
        catch (IOException ex) {
            throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
        }
    }

}

查询到的一些教程:EnvironmentPostProcessor in Spring Boot

思路

我们可以通过自定义Environment,来在应用程序上下问创建之前,获取配置文件的属性信息进行相应的操作,来达到我们想要的配置文件加密解密效果。

自定义实现

创建一个项目文件在里面添加一个类SafetyEncryptProcessor通过实现EnvironmentPostProcessorpostProcessEnvironment方法,然后将EnvironmentPostProcessor注册到文件META-INF/spring.factories,然后让其他应用程序依赖,这样我们可以实现对配置文件相应配置的修改,简单示例如下:
项目目录结构项目目录结构

package com.tools.encrypt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;

import java.util.HashMap;

/**
 * @author Mr.Deng
 * @date 2020/8/6 18:00
 * <p>Copyright: Copyright (c) 2020</p>
 */
public class SafetyEncryptProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
      
        HashMap<String, Object> map = new HashMap<>();
        for (PropertySource<?> ps : environment.getPropertySources()) {
            if (ps instanceof OriginTrackedMapPropertySource) {
                OriginTrackedMapPropertySource source = (OriginTrackedMapPropertySource) ps;
                for (String name : source.getPropertyNames()) {
                    Object value = source.getProperty(name);
                    System.out.println("value ======= " + value);
                    if (value instanceof String) {
                        String str = (String) value;
                        if (str.startsWith("mpen:")) { //mpen:  需要处理的value的前缀
                            map.put(name, "123456");     //此处的12345可自定义为对value的处理
                           }
                    }
                }
            }
        }
        // 将处理的数据放入环境变量,并处于第一优先级上 (这里一定要注意,覆盖其他配置)
        if (!map.isEmpty()) {
            environment.getPropertySources().addFirst(new MapPropertySource("prefixer", map));
        }
    }
}

META-INF/spring.factories配置

org.springframework.boot.env.EnvironmentPostProcessor=\
  com.tools.encrypt.SafetyEncryptProcessor

pom引入jar

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.tools</groupId>
        <artifactId>cloud-tools-common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>cloud-common-encrypt</artifactId>
    <name>cloud-common-encrypt</name>
    <modelVersion>4.0.0</modelVersion>
    <description>配置文件加解密</description>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

调用应用程序

  1. 引入pom
<dependency>
   <groupId>com.tools</groupId>
   <artifactId>cloud-common-encrypt</artifactId>
   <version>0.0.1-SNAPSHOT</version>
</dependency>
  1. 配置文件使用
my:
  name:  mpen:abcdefg
  1. 然后运行调用引用程序
    就可以查看到my.name的配置属性的值读出来是123456,而不是配置文件里面写的** mpen:abcdefg**了。

总结

当然这里只是提到了思路和简单的实现,然而密码加密的实现可以参考自定义实现 对value进行解密处理,然后添加加密模块,或者添加自定义自动配置,进行相关的密钥的配置来使得配置文件加密的密文更加的安全。

这些都是自己的见解,如有什么不足之处,欢迎留言交流,谢谢阅读:)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐