一,背景
突然有一天,接到个需求,要求项目的敏感配置不能用明文,需要密文,比如数据库密码。
二,思路
有一个同事是这样实现的
@Component
public class DatasourceConfig {
@Bean
public DataSource getDs(BeanConfig config) {
HikariDataSource dataSource = new HikariDataSource();
// 密钥(需要保管好,256位)
byte[] key = "12345678123456781234567812345678".getBytes();
dataSource.setPassword(new AES(key).encryptHex(config.getValue()));
return dataSource;
}
}
思路:在mysql,datasource初始化的时候,指定解密一下,能快速实现这个需求。
三,缺点
很明显,所有配置项都能这么搞,但需要写很多的属性解析,增加很多工作量。 从二开框架的角度看,也很不优雅。
四,思考
利用spring的开的口子,像是ApplicationContextAware都可以做,我们用EnvironmentPostProcessor来实现:
1,首先在spring.factories里增加配置,将我们的扩展处理程序注入进去。
org.springframework.boot.env.EnvironmentPostProcessor = com.web.extend.Deserialize
2,实现扩展程序
@Slf4j
public class Deserialize 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);
if (value instanceof String) {
//特殊标识的内容,要转换成明文
if (((String) value).startsWith("ENC_")) {
map.put(name, ((String) value).replace("ENC_", ""));
}
}
}
//将属性放置回去,在原配置的前面,保证优先级
if (!map.isEmpty()) {
environment.getPropertySources().addBefore(source.getName(),new MapPropertySource("new", map));
}
}
}
}
}
3,效果
五,扩展
对公司框架进行二开的时候,约定好密文的开头,就可以实现啦。