1

许多项目里会对配置文件中的敏高文件进行加密处理,避免了信息泄露问题。在springboot项目里,可以通过引入jasypt进行密码密文存放

jasypt使用

1.引入jasypt-spring-boot-starter包

image.png

2.配置信息

jasypt:
  encryptor:
    algorithm: PBEWithHMACSHA512AndAES_256
    password: 123456 //salt

或将password放在启动行参数里

image.png

3.启动项添加注解

image.png

4.生成密文

可以通过网上的密码工具生成,也可以使用jasypt生成

AES256TextEncryptor stringEncryptor = new AES256TextEncryptor();
stringEncryptor.setPassword("123456");  //salt
String encrypt = stringEncryptor.encrypt("test");  //加密 test为你的密码
String decrypt = stringEncryptor.decrypt(encrypt); //解密

5.将生成的encrypt放到原来的密码处并用ENC()包裹即可,ENC()可通过jasypt.encryptor.algorithm.property.prefix/suffix进行配置

test: ENC(sdjflskdjfsjdflksdjalfjdslkfjksdjfkldsjkfsf) //此处放上面生成的encrypt
jasypt:
  encryptor:
    algorithm: PBEWithHMACSHA512AndAES_256
    property:
      prefix:   #默认为ENC(
      suffix:   #默认为)

与Dubbo联用

它会存在一个问题,就是无法对dubbo的配置进行加密,解决方法如下:

方法

  1. 将下面文件添加到项目里,目前仅支持PBEWithHMACSHA512AndAES_256,如需要支持其他,可自行在TODO处添加处理逻辑

    //JasyptPreparedEnvListener.java
    package test.listener;
    
    import org.jasypt.util.text.AES256TextEncryptor;
    import org.springframework.boot.context.config.ConfigFileApplicationListener;
    import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.event.SmartApplicationListener;
    import org.springframework.core.Ordered;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.core.env.PropertySource;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.stream.Stream;
    
    public class JasyptPreparedEnvListener implements SmartApplicationListener, Ordered {
    
         private String getSalt(ConfigurableEnvironment env ){
         String salt = env.getProperty("jasypt.encryptor.password");
    
         if(salt == null || salt.isBlank()) {
             return null;
         }
    
         return salt;
     }
    
     private String[] getConfigAllows(ConfigurableEnvironment env ){
         String rst = env.getProperty("jasypt.encryptor.property.config.allows");
    
         String[] rstArr;
    
         if(rst == null || rst.isBlank()) {
             rstArr = new String[]{"dubbo."};
             return rstArr;
         }else{
             rstArr = Stream.of(rst.split(",")).map(val->val+".").toArray(String[]::new);
         }
    
         return rstArr;
     }
    
     private String getConfigPrefix(ConfigurableEnvironment env ){
         String rst = env.getProperty("jasypt.encryptor.property.config.prefix");
    
         if(rst == null || rst.isBlank()) {
             rst = env.getProperty("jasypt.encryptor.property.prefix");
         }
    
         if(rst == null || rst.isBlank()) {
             return "ENC(";
         }
    
         return rst;
     }
    
     private String getConfigSuffix(ConfigurableEnvironment env ){
         String rst = env.getProperty("jasypt.encryptor.property.config.suffix");
    
         if(rst == null || rst.isBlank()) {
             rst = env.getProperty("jasypt.encryptor.property.suffix");
         }
    
         if(rst == null || rst.isBlank()) {
             return ")";
         }
    
         return rst;
     }
    
     private boolean shouldDecrypted(String[] allows,String value){
         if(value == null || value.isBlank()){
             return false;
         }
    
         String trimValue = value.trim();
    
         boolean rst = false;
    
         for(String allow : allows){
             if(trimValue.startsWith(allow)){
                 rst = true;
             }
         }
    
         return rst;
     }
    
     private boolean isEncrypted(String value,String prefix,String suffix){
         if(value == null || value.isBlank()){
             return false;
         }
    
         String trimValue = value.trim();
         return trimValue.startsWith(prefix) && trimValue.endsWith(suffix);
     }
    
     private String unwrapEncryptedValue(String value,String prefix,String suffix){
         return value.substring(prefix.length(),value.length() - suffix.length());
     }
    
     private String getAlgorithm(ConfigurableEnvironment env){
         String rst = env.getProperty("jasypt.encryptor.algorithm");
    
         if(rst == null || rst.isBlank()) {
             return "PBEWithHMACSHA512AndAES_256";
         }
    
         return rst;
     }
    
     private Object getDecryptor(ConfigurableEnvironment env){
    
         String algorithm = getAlgorithm(env);
    
         Object obj = null;
    
         if(algorithm.equals("PBEWithHMACSHA512AndAES_256")){
             String salt = getSalt(env);
             if(salt != null){
                 obj = new AES256TextEncryptor();
                 ((AES256TextEncryptor)obj).setPassword(salt);
             }
         }//add other decryptor logic here
    
         return obj;
     }
    
     private String decrypt(ConfigurableEnvironment env,Object decryptpr,String value){
    
         String algorithm = getAlgorithm(env);
    
         if(algorithm.equals("PBEWithHMACSHA512AndAES_256")){
            AES256TextEncryptor aes256TextEncryptor = (AES256TextEncryptor)decryptpr;
             try{
                 return aes256TextEncryptor.decrypt(value);
             }catch (Exception e){
                 System.out.println("decrypt failed: " + e);
                 return value;
             }
         } //add other decryptor logic here
         return value;
     }
    
     @Override
     public void onApplicationEvent(ApplicationEvent applicationEvent) {
         ConfigurableEnvironment env = ((ApplicationEnvironmentPreparedEvent)applicationEvent).getEnvironment();
         // 1. get decryptor
         Object decryptor = getDecryptor(env);
    
         if(decryptor == null){
             return;
         }
    
         String configPrefix = getConfigPrefix(env);
         String configSuffix = getConfigSuffix(env);
         String[] configAllows = getConfigAllows(env);
    
         // 2. loop property
         Iterator<PropertySource<?>> iterator = env.getPropertySources().iterator();
         while (iterator.hasNext()) {
             PropertySource<?> source = iterator.next();
             Object o = source.getSource();
             if (o instanceof Map) {
                 for (Map.Entry<String, Object> entry : ((Map<String, Object>) o).entrySet()) {
                     String key = entry.getKey();
                     String value = env.getProperty(key);
    
                     if (shouldDecrypted(configAllows,key) && isEncrypted(value, configPrefix, configSuffix)) {
                         //3.解密
                         String newValue = decrypt(env, decryptor, unwrapEncryptedValue(value, configPrefix, configSuffix));
                         System.setProperty(key, newValue);
                     }
                 }
             }
         }
     }
    
     @Override
     public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
         return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(aClass);
     }
    
     @Override
     public int getOrder() {
         return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
     }
    }
    
  2. 添加配置(三选一即可)

application.properties(多个监听器用,隔开)

context.listener.classes: test.listener.JasyptPreparedEnvListener

application.yml(多个监听器用,隔开)

context:
  listener:
    classes: test.listener.JasyptPreparedEnvListener

启动项里api添加

SpringApplication app = new SpringApplication(App.class);
app.addListeners(new JasyptPreparedEnvListener());
app.run(args);
  1. 将需要密文存储的地方使用ENC()包裹即可
dubbo:
    registries:
        password: ENC(fdsfsdfsd)

修改配置

jasypt:
  encryptor:
    algorithm: PBEWithHMACSHA512AndAES_256
    property:
      config:
        prefix:   #默认取jasypt.encryptor.property.prefix的配置,如果没有则为ENC(
        suffix:   #同prefix
        allows:   #允许更新的值的prefix 默认为dubbo 多个使用,隔开 (例dubbo或dubbo.registries或dubbo,mail)  

它的思路就是在Springboot的ApplicationEnvironmentPreparedEvent事件里对配置文件信息进行处理

ApplicationEnvironmentPreparedEvent: spring boot 对应Enviroment已经准备完毕,但此时上下文context还没有创建。在该监听中获取到ConfigurableEnvironment后可以对配置信息做操作,例如:修改默认的配置信息,增加额外的配置信息等等

点墨
26 声望3 粉丝

全栈前端开发工程师