如何添加含{cipher}加密属性的外部PropertySource并实现自动解密?
如何解密外部属性源中的{cipher}加密属性
一、Spring能解密application-*.yml中{cipher}属性的原因
Spring Boot(通常配合Spring Cloud Config)对内置配置文件的解密是在属性加载阶段自动完成的:
- 对于application-*.yml这类文件,Spring会通过专用加载器(如
YamlPropertySourceLoader)读取,这些加载器集成了解密逻辑。 - 加载时会自动识别带
{cipher}前缀的属性值,调用对应解密组件(如CipherResourceYamlEncryptor)完成解密,再将解密后的值注入环境。整个流程是配置加载的固有环节,无需额外操作。
二、让外部PropertiesPropertySource属性自动解密的方案
你的问题出在直接将未解密的Properties对象添加到环境中,跳过了Spring的解密流程。以下两种方案可以解决:
方案1:手动调用解密器预处理Properties
在添加属性源前,先手动处理Properties中的加密属性。需要先初始化解密器(依赖环境中的加密配置,如密钥),再遍历属性完成解密:
import org.springframework.cloud.context.encrypt.EncryptorFactoryBean; import org.springframework.core.env.Environment; import org.springframework.security.crypto.encrypt.TextEncryptor; import java.util.Properties; import java.util.Set; public class PropertyDecryptor { public static Properties decrypt(Properties rawProps, Environment env) { TextEncryptor encryptor = createTextEncryptor(env); Properties decryptedProps = new Properties(); Set<String> keys = rawProps.stringPropertyNames(); for (String key : keys) { String value = rawProps.getProperty(key); if (value != null && value.startsWith("{cipher}")) { String encryptedContent = value.substring("{cipher}".length()); decryptedProps.setProperty(key, encryptor.decrypt(encryptedContent)); } else { decryptedProps.setProperty(key, value); } } return decryptedProps; } private static TextEncryptor createTextEncryptor(Environment env) { EncryptorFactoryBean factory = new EncryptorFactoryBean(); factory.setEnvironment(env); try { factory.afterPropertiesSet(); return factory.getObject(); } catch (Exception e) { throw new RuntimeException("Failed to initialize decryptor", e); } } }
在监听器中使用:
class MyApplicationContextListener implements ApplicationListener<ApplicationContextInitializedEvent> { @Override public void onApplicationEvent(ApplicationContextInitializedEvent event) { ConfigurableEnvironment env = event.getApplicationContext().getEnvironment(); Properties decryptedProps = PropertyDecryptor.decrypt(properties, env); env.getPropertySources().addLast(new PropertiesPropertySource(sourceName, decryptedProps)); } }
方案2:用EncryptablePropertySource包装原属性源
如果是Spring Cloud环境,直接用EncryptablePropertySource包装你的属性源,它会自动处理解密逻辑:
import org.springframework.cloud.context.environment.EncryptablePropertySource; import org.springframework.core.env.ConfigurableEnvironment; class MyApplicationContextListener implements ApplicationListener<ApplicationContextInitializedEvent> { @Override public void onApplicationEvent(ApplicationContextInitializedEvent event) { ConfigurableEnvironment env = event.getApplicationContext().getEnvironment(); PropertiesPropertySource rawSource = new PropertiesPropertySource(sourceName, properties); EncryptablePropertySource encryptableSource = new EncryptablePropertySource(rawSource.getName(), rawSource.getSource(), env); env.getPropertySources().addLast(encryptableSource); } }
注意事项
- 确保加密配置(如
encrypt.key)在添加外部属性源前已加载(比如来自application.yml),否则解密器无法初始化。 - 若使用自定义加密逻辑,需替换对应的解密实现,而非依赖Spring Cloud默认组件。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

