java - 应用程序监听器中的 Spring 加载应用程序属性

标签 java spring spring-boot spring-mvc encryption

我正在尝试监听 Spring 中的应用程序事件并解密已加密的应用程序属性(具有加密前缀)。我们的想法是创建一个 Spring 组件,如果属性值被加密,该组件将在加载环境时自动解密 spring 属性。

这需要与具有 application.env.properties 文件的旧版 Spring 应用程序(没有 Spring Boot)以及具有 yaml 文件中定义的属性的最新 Spring Boot 应用程序一起使用。应该能够解密任何 Spring 属性,无论源,不应依赖于 Spring Boot 并适用于任何 Spring 版本。

public class DecryptingPropertiesListener
    implements ApplicationListener<ContextRefreshedEvent>, Ordered {
public static final String PREFIX_KEY = "{decrypt}";

private String prefix;
private Encrypter encrypter = Encrypter.defaultInstance();

@Override
public void onApplicationEvent(ContextRefreshedEvent event ) {
    Environment environment = event.getApplicationContext().getEnvironment();
    prefix = environment.getProperty(PREFIX_KEY, "{encrypted}");

    final MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();

    Set<String> encryptedKeys = getKeysOfEncryptedPropertyValues(environment, propertySources);
    addDecryptedValues(environment, propertySources, encryptedKeys);
}

private Set<String> getKeysOfEncryptedPropertyValues(Environment environment, MutablePropertySources propertySources) {
    return streamFromIterator(propertySources.iterator())
            .filter(EnumerablePropertySource.class::isInstance)
            .map(EnumerablePropertySource.class::cast)
            .flatMap(source -> asList(source.getPropertyNames()).stream())
            .filter(this::isNotEncryptionConfigProperty)
            .filter(key -> isEncrypted(environment.getProperty(key)))
            .collect(toSet());
}

private boolean isNotEncryptionConfigProperty(String key) {
    return !PREFIX_KEY.equals(key);
}

private Stream<PropertySource<?>> streamFromIterator(Iterator<PropertySource<?>> iterator) {
    Iterable<PropertySource<?>> iterable = () -> iterator;
    return StreamSupport.stream(iterable.spliterator(), false);
}

private void addDecryptedValues(Environment environment, MutablePropertySources propertySources, Set<String> encryptedKeys) {
    Map<String, Object> decryptedProperties = encryptedKeys.stream()
            .collect(toMap(
                    key -> key,
                    key -> decryptPropertyValue(environment.getProperty(key))));
    propertySources.addFirst(new MapPropertySource("decryptedValues", decryptedProperties));
}

private String decryptPropertyValue(String encryptedPropertyValue) {
    try {
        return encrypter.decryptIfEncrypted(encryptedPropertyValue);
    }
    catch (EncryptionException e) {
        throw new RuntimeException("Unable to decrypt property value '" + encryptedPropertyValue + "'", e);
    }
}

private boolean isEncrypted(Object propertyValue) {
    return propertyValue != null && propertyValue instanceof String && ((String)propertyValue).startsWith(prefix);
}

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

但问题是,我没有看到这一行返回的应用程序属性,((ConfigurableEnvironment)environment).getPropertySources(); 我可以在这里看到系统属性,但看不到应用程序。知道如何在此处加载应用程序属性并解密它们吗? 谢谢

编辑:添加示例属性文件。这个想法是将这个通用 jar 添加为各种 Web 应用程序(旧版和新的 Spring Boot 应用程序)的 Maven 依赖项。 以下属性文件的格式为 myapp.env.properties,并且 myapp.system.properties 已定义 env。但 Spring Boot 应用程序使用 .yaml 文件。服务和安全密码需要解密,因为它们有前缀。

base.url=http://localhost:8080/myapp
service.password={decrypt}123456789==
security.password={decrypt}abcdefgh==
help.email.address=support@gmail.com

最佳答案

您可以使用EncryptablePropertyPlaceholderConfigurer并提供StringEncryptor实例,它将为您处理属性的解密。如果需要,您还可以扩展该类以加载额外的属性。

示例:


@Configuration
public class PropertyConfiguration {

  @Bean(name="envPropertyConfigurer")
  public EncryptablePropertyPlaceholderConfigurer getConfigurer() {
      return new EncryptablePropertyPlaceholderConfigurer (encryptor());
  }

  private StringEncryptor encryptor() {
     StandardPBEStringEncryptor s_encryptor = new StandardPBEStringEncryptor();
     s_encryptor.setAlgorithm("PBEWithMD5AndDES");
     s_encryptor.setPassword("secretKey");
     return s_encryptor;
  }
}

你也可以在 spring xml 配置中这样做

<bean id="envPropertyEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
    <property name="algorithm" value="PBEWithMD5AndDES" />
    <property name="algorithm" value="secretKey" />
</bean>
<bean id="envPropertyConfigurer" class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
     <constructor-arg ref="envPropertyEncryptor" />
</bean>

您还可以从文件中读取 key ,而不是直接在此处设置它。您可以通过使用 FileStringPBEConfig 设置 StandardPBEStringEncryptor config 属性来实现此目的。

关于java - 应用程序监听器中的 Spring 加载应用程序属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56372260/

相关文章:

java - 有什么方法可以在 Spring ApplicationContext 加载后像带注释的类一样扫描所有 @Component

java mysql for循环中的结果集错误

json - 使用 Jackson 将列表转换为 json

java - @OneToMany 中未填充父实体。 hibernate 双向

java - Spring框架请求范围和单例 Autowiring

java - Mybatis 一对多的集合映射总是有一个默认实体

java - 文件扩展名上的spring requestmapping http错误406

java - org.apache.catalina.LifecycleException : Failed to start component [StandardEngine[Catalina]. 标准主机

java - 为什么我们必须为不抛出异常的方法处理异常?

java - 我已正确更改 JAVA_HOME 和 PATH,但我看到错误的 java 版本。为什么? ( Windows )