我正在尝试监听 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/