一般情况下,我们做项目的时候,中间件例如mysql,redis, zk 的账号密码一般都是写在配置文件里面的, 这样代码泄露的情况下, 就很不安全。
由第三方的加密的工具 jasypt 这种jar包。 这里我们仿写它来实现自己的配置文件加密规则。
jasypt 连接:https://github.com/ulisesbocchio/jasypt-spring-boot
具体的使用大家看我发的地址。
这里我们要用到ConfigurableEnviroment 这个类,我们来看一下源码
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
void setActiveProfiles(String... var1);
void addActiveProfile(String var1);
void setDefaultProfiles(String... var1);
// resource 文件多个,这个可以是classpath ,file ,default 的
MutablePropertySources getPropertySources();
// 获取系统配置文件
Map<String, Object> getSystemProperties();
// 获取系统环境变量
Map<String, Object> getSystemEnvironment();
void merge(ConfigurableEnvironment var1);
}
首先我们要自己写一个类实现BeanFactoryPostProcessor ,和order 接口
public class PropertiesEncryptionConfig implements BeanFactoryPostProcessor, Ordered {
// 前缀的key
public static final String PREFIX_PROPERTY = "xxxxx.encrypt.prefix";
// 后缀的key
public static final String SUFFIX_PROPERTY = "xxxxx.encrypt.suffix";
// 私钥的key
public static final String RSA_PRIVATE_KEY_PROPERTY = "xxxxx.encrypt.privateKey";
// 前缀默认值
public static final String DEFAULT_PREFIX = "xxxxx[";
//后缀默认值
public static final String DEFAULT_SUFFIX = "]";
private static final Logger LOG = LoggerFactory.getLogger(PropertiesEncryptionConfig.class);
// 在通过@bean 注入进来
public ConfigurableEnvironment environment ;
public PropertiesEncryptionConfig(ConfigurableEnvironment environment) {
this.environment = environment;
}
private String prefix;
private String suffix;
private String privateKey;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
MutablePropertySources propertySources = environment.getPropertySources();
for (PropertySource<?> propertySource : propertySources) {
if (propertySource instanceof OriginTrackedMapPropertySource) {
// 只有这个才是加载properties 文件的,getsource 返回的就是map
OriginTrackedMapPropertySource om = (OriginTrackedMapPropertySource) propertySource;
Map<String, Object> source = om.getSource();
source.forEach((k, v) -> {
String property = environment.getProperty(k);
if (hasPreAndSuf(property)) {
LOG.info("开始处理 k = [{}]", k);
try {
String relay = splitPreAndSuf(property, this.prefix, this.suffix);
// 这里获取去掉前缀后缀的值 在通过自己的解密规则 ,
//这里 AesUtils 可以搞成注入模式, 这样使用的时候可以进行加密。自己写aes 的加密工具类
String decrypt = AesUtils.aesDecrypt(relay, getPrivateKey(environment));
source.put(k, decrypt);
}
catch (Exception e) {
LOG.error("配置文件加密异常错误信息: ", e);
}
}
});
}
}
}
private String getPrivateKey(ConfigurableEnvironment environment) throws Exception {
// 支持从系统环境变量 java -jar 运行的时候获取
this.privateKey = System.getProperty(RSA_PRIVATE_KEY_PROPERTY, "");
if (StringUtils.hasText(this.privateKey)) {
return this.privateKey;
}
// 支持从文件获取
this.privateKey = environment.getProperty(RSA_PRIVATE_KEY_PROPERTY);
if (StringUtils.hasText(this.privateKey)) {
return this.privateKey;
}
// 都没有就会报错
throw new Exception(" properties aes private key is null!");
}
// 判断一下,前缀后缀是否匹配
private boolean hasPreAndSuf(String property) {
return property.startsWith(getPrefix(environment)) && property.endsWith(getSuffix(environment));
}
// 去掉前缀后缀获取中间值
protected String splitPreAndSuf(String str, String prefix, String suffix) {
return str.replace(prefix, "").replace(suffix, "");
}
// 获取后缀,没有使用默认值
private String getSuffix(ConfigurableEnvironment environment) {
this.suffix = environment.getProperty(SUFFIX_PROPERTY);
if (StringUtils.hasLength(suffix)) {
return this.suffix;
}
this.suffix = DEFAULT_SUFFIX;
return DEFAULT_SUFFIX;
}
// 获取前缀,使用默认值
private String getPrefix(ConfigurableEnvironment environment) {
this.prefix = environment.getProperty(PREFIX_PROPERTY);
if (StringUtils.hasLength(prefix)) {
return this.prefix;
}
this.prefix = DEFAULT_PREFIX;
return DEFAULT_PREFIX;
}
/**
* 提高优先级
* @return
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE -100;
}
}
@Configuration
public class EnablePropertiesEncryption {
@Bean
public PropertiesEncryptionConfig getPropertiesEncryption(ConfigurableEnvironment configurableEnvironment){
return new PropertiesEncryptionConfig(configurableEnvironment);
}
// 加密解密工具类 ,可以在spring单元测试使用@Autowired注入
@Bean
public AesUtils getAes(){
return new AesUtils();
}
}
这样我们就基本实现了jasypt 的功能。