篇序: 在springboot开发过程中,需要配置很多信息在配置文件里,如果数据不加密,传明文,如数据库什么的就直接暴露了,存在安全隐患,因此需要进行加密处理才行。配置文件是密文,在代码实际使用过程中解密信息成明文,供程序使用。
这里有一个别人已经封装完善的jar包工具, jaypt大家有兴趣的话可以自行了解,因为他封装的代码太多,我这边只记录我自己的理解使用。 没有那么通用性,扩展的话,可以向其学习,多了解下源码,我这的可以直接搬砖。
注意:有很多什么如对称加密算法,非对称加密算法,什么加盐salt之类的,就自行了解了,推荐几种:AES、RSA、ECC、SHA。 安全性更高之类的,增加伪随机数,想学习的可以研究下。
前提要有自己的加解密工具类,我用的AES。
配置示例
demo:
password: ENC(nGkRyFhFQoicg4xtPtF5ag==)
开始
关键类BeanFactoryPostProcessor
/**
* 定义一个属性注入替换
*/
public class EnableEncryptablePropertiesBeanFactoryPostProcessor implements BeanPostProcessor, Ordered {
private final ConfigurableEnvironment environment;
private final EncryptablePropertyResolver encryptablePropertyResolver;
public EnableEncryptablePropertiesBeanFactoryPostProcessor(ConfigurableEnvironment environment, EncryptablePropertyResolver encryptablePropertyResolver) {
this.environment = environment;
this.encryptablePropertyResolver = encryptablePropertyResolver;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.forEach(pv -> {
PropertySource propertySource = propertySources.get(pv.getName());
if(propertySource instanceof MapPropertySource){
Map<String, Object> convertPropertySource = new HashMap<String, Object>();
MapPropertySource newMapPropertySource = new MapPropertySource(pv.getName(), convertPropertySource);
String[] propertyNames = ((MapPropertySource) propertySource).getPropertyNames();
for (String propertyName : propertyNames) {
Object value = propertySource.getProperty(propertyName);
if(value instanceof String){
convertPropertySource.put(propertyName, encryptablePropertyResolver.resolvePropertyValue((String)value));
}else{
convertPropertySource.put(propertyName, value);
}
}
propertySources.replace(pv.getName(), newMapPropertySource);
}
});
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 100;
}
}
将其类和加密工具方法注入spring的容器管理
@Configuration
public class LocalPropertySourcesPlaceholderConfigurer {
@Bean
public EncryptablePropertyResolver encryptablePropertyResolver(){
return new DefalutPropertyResolver(new DefalutEncryptor());
}
@Bean
public EnableEncryptablePropertiesBeanFactoryPostProcessor enableEncryptablePropertiesBeanFactoryPostProcessor(
final ConfigurableEnvironment environment, EncryptablePropertyResolver encryptablePropertyResolver){
return new EnableEncryptablePropertiesBeanFactoryPostProcessor(environment, encryptablePropertyResolver);
}
}
解密过程
public class DefalutPropertyResolver implements EncryptablePropertyResolver {
/**
* 扩展性:
* 像这些可以单独弄在配置文件里,便于扩展,也可以配置属于自己的加接密类,进行解密。
* 封装成自己的jar工具包,增强提供通用性。
*/
private StringEncryptor encryptor;
private String prefix = "ENC(";
private String suffix = ")";
public DefalutPropertyResolver(StringEncryptor encryptor) {
this.encryptor = encryptor;
}
@Override
public String resolvePropertyValue(String value) {
return Optional.ofNullable(value)
.filter(this::isEncrypted)
.map(resolvedValue -> {
String unwrappedProperty = resolvedValue.trim().substring(prefix.length(), resolvedValue.length() - suffix.length());
return encryptor.decrypt(unwrappedProperty);
})
.orElse(value);
}
private boolean isEncrypted(String property){
if(property == null){
return false;
}
final String trimValue= property.trim();
return (trimValue.startsWith(prefix) &&
trimValue.endsWith(suffix));
}
}
结语
像这种加密类的,可以自己封装成通用的jar工具通用项目,不用每次新项目都要重新敲一遍,因为自己懒。 像jasypt虽然封装的很好,但是源码太多太乱了,还是自己封装一遍会好一点,根据自己的需要来取用。