Spring属性解密

时间:2019-05-05 21:42:34

标签: java spring spring-boot encryption properties

我们混合了一些尚未迁移到spring-boot或spring cloud的旧版spring应用程序,以及spring boot应用程序。我正在创建一个Spring组件,该组件将在加载环境时自动解密spring属性(如果属性值已加密并具有前缀)。这些属性可以在.properties文件中(对于旧版应用程序)或在.yaml文件中(较新的Spring Boot应用程序)。

该组件应该能够解密任何spring属性,而不管其来源是什么,并且应该可以与任何spring版本一起使用并且不依赖于spring boot。组件还应该透明地解密属性。它应该从属性文件中读取密码,因此密码文件需要从头开始加载。

我们有自己的加密/解密工具,不想使用jaspyt。

到目前为止已尝试过的事情:

我喜欢使用this创建ApplicationListener的方法,但这与Spring Boot(ApplicationEnvironmentPreparedEvent)捆绑在一起。使用诸如ContextRefreshed或ContextStart之类的Spring事件,我看不到如何获得ConfigurableApplicationContext / ConfigurableEnvironment。是否有人在没有Spring Boot / Cloud的情况下创建了用于加密/解密的监听器?

我还创建了一个自定义的ApplicationContextInitializer,并将其添加到web.xml的context-param中,但这似乎不起作用。当我调试它时,我不认为它正在从我的app.properties文件中加载/读取属性。

       @Component
    public class DecryptingPropertyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
       public void initialize( ConfigurableApplicationContext applicationContext ) {
          ConfigurableEnvironment environment = applicationContext.getEnvironment();
          for ( PropertySource<?> propertySource : environment.getPropertySources() ) {
             Map<String, Object> propertyOverrides = new LinkedHashMap<>();
             decodePasswords( propertySource, propertyOverrides );
             if ( !propertyOverrides.isEmpty() ) {
                PropertySource<?> decodedProperties = new MapPropertySource( "decoded " + propertySource.getName(),
                      propertyOverrides );
                environment.getPropertySources().addBefore( propertySource.getName(), decodedProperties );
             }
          }
       }

        private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
          if ( source instanceof EnumerablePropertySource ) {
             EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
             for ( String key : enumerablePropertySource.getPropertyNames() ) {
                Object rawValue = source.getProperty( key );
                if ( rawValue instanceof String ) {
                   //decrypt logic here
propertyOverrides.put( key, decryptedValue );
                }
             }
          }
        }
    }

有人需要做类似的事情或有更好的主意吗?有没有一种方法可以监听应用程序事件然后进行处理? 感谢您的帮助

1 个答案:

答案 0 :(得分:2)

您可以编写自己的PropertiesFactoryBean并覆盖createProperties来解密加密的值:

public class DecryptingPropertiesFactoryBean extends PropertiesFactoryBean {
  @Override
  protected Properties createProperties() throws IOException {
    final Properties encryptedProperties = super.createProperties();
    final Properties decryptedProperties = decrypt(encryptedProperties);
    return decryptedProperties;
  }
}

和使用以下属性的PropertySourcesPlaceholderConfigurer bean:

@Configuration
public class PropertiesConfiguration {

  @Bean
  public static DecryptingPropertiesFactoryBean propertyFactory() {
    final DecryptingPropertiesFactoryBean factory = new DecryptingPropertiesFactoryBean();
    final Resource[] propertyLocations = new Resource[] {
        new FileSystemResource(new File("path/to/file.properties"))
    };
    factory.setLocations(propertyLocations);
    return factory;
  }

  @Bean
  public static Properties properties() throws Exception {
    return propertyFactory().getObject();
  }

  @Bean
  public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    final PropertySourcesPlaceholderConfigurer bean = new PropertySourcesPlaceholderConfigurer();
    bean.setIgnoreResourceNotFound(true);
    bean.setIgnoreUnresolvablePlaceholders(false);
    bean.setProperties(properties());
    return bean;
  }
}