SpringBoot:整合jasypt


整合SpringBoot

官方文檔:https://github.com/ulisesbocchio/jasypt-spring-boot

據官方文檔介紹有三種方式可以引入jasypt

第一種

直接引入jasypt的starter

<dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>3.0.3</version>
</dependency>

第二種

引入

<dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot</artifactId>
        <version>3.0.3</version>
</dependency>

然后添加@EnableEncryptableProperties在你的配置類上

第三種

引入

dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot</artifactId>
        <version>3.0.3</version>
</dependency>

然后在配置類上配置如下:

@Configuration
@EncryptablePropertySource(name = "EncryptedProperties", value = "classpath:encrypted.properties")
public class MyApplication {
}

同時支持多個@EncryptablePropertySource注解,如下:

@Configuration
@EncryptablePropertySources({@EncryptablePropertySource("classpath:encrypted.properties"),
                             @EncryptablePropertySource("classpath:encrypted2.properties")})
public class MyApplication {

}

1.8以后,配置文件支持yaml格式。

自定義環境

我們可以這樣配置自己的環境。此方法對於早期訪問springboot引導的加密屬性的非常有用。

new SpringApplicationBuilder()
    .environment(new StandardEncryptableServletEnvironment())
    .sources(YourApplicationClass.class).run(args);

此外,我們可以配置StandardEncryptableServletEnvironment

StandardEncryptableServletEnvironment env = StandardEncryptableServletEnvironment
    .builder()
    .encryptor(new StandardPBEStringEncryptor())
    .build();

new SpringApplicationBuilder()
    .environment(env)
    .sources(BootJasyptApplication.class).run(args);

基於密碼的加密配置

所有的配置項都在JasyptEncryptorConfigurationProperties類屬性中,我們直需要在yml中配置屬性,就可以達到重寫的目的。

Jasypt使用StringEncryptor來解密屬性。對於上述所有3個配置方法,如果在Spring上下文中找不到自定義StringEncryptor(有關詳細信息,請參閱自定義Encryptor部分),則會自動創建一個,可以通過以下屬性(系統、屬性文件、命令行參數、環境變量等)進行配置:

image-20210507101847493

唯一需要的屬性是加密密碼,其余的可以使用默認值。雖然所有這些屬性都可以在屬性文件中聲明,但加密程序密碼不應該存儲在屬性文件中,而應該作為系統屬性、命令行參數或環境變量傳遞,只要它的名稱是jasypt.encryptor.password,它就可以工作。

最后一個屬性jasypt.encryptor.proxyPropertySources用於指示jasyp spring boot如何攔截屬性值進行解密。默認值false使用PropertySource、EnumerablePropertySource和MapPropertySource的自定義包裝器實現。當為此屬性指定true時,攔截機制將在每個特定的PropertySource實現上使用CGLib代理。在某些必須保留原始PropertySource類型的場景中,這可能很有用。

自定義加密

默認情況下,bean容器會配置LazyJasyptStringEncryptor

對於加密程序和加密程序密碼源的自定義配置,您始終可以在Spring上下文中定義自己的StringEncryptor bean,默認的加密程序將被忽略

  @Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
    PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
    SimpleStringPBEConfig config = new SimpleStringPBEConfig();
    config.setPassword("password");
    config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
    config.setKeyObtentionIterations("1000");
    config.setPoolSize("1");
    config.setProviderName("SunJCE");
    config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
    config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
    config.setStringOutputType("base64");
    encryptor.setConfig(config);
    return encryptor;
}

注意,bean名稱是必需的,因為jasypt-spring-boot從版本1.5開始按名稱檢測自定義字符串jasyptStringEncryptor

自定義屬性探測器、前綴、后綴和/或解析器

從jasypt-spring-boot-1.10開始,有新的可擴展點。EncryptablePropertySource現在使用EncryptablePropertyResolver解析所有屬性

public interface EncryptablePropertyResolver {
    String resolvePropertyValue(String value);
}

這個接口的實現負責檢測和解密屬性。默認實現DefaultPropertyResolver使用前面提到的StringEncryptor和新的EncryptablePropertyDetector

自定義屬性探測器

您可以通過提供一個名為EncryptablePropertyDetector的EncryptablePropertyDetector類型的Bean來覆蓋默認實現,或者如果您想提供自己的Bean名稱,請覆蓋屬性jasypt.encryptor.property.detector-Bean並指定您想給Bean的名稱。當提供這個時,您將負責檢測加密屬性。例子:

    @Bean(name = "encryptablePropertyDetector")
    public EncryptablePropertyDetector encryptablePropertyDetector() {
        return new MyEncryptablePropertyDetector();
    }

    private static class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {
        @Override
        public boolean isEncrypted(String value) {
            if (value != null) {
                return value.startsWith("ENC@");
            }
            return false;
        }

        @Override
        public String unwrapEncryptedValue(String value) {
            return value.substring("ENC@".length());
        }
    }

提供自定義的加密屬性前綴和后綴

如果您只想為加密屬性設置不同的前綴/后綴,則可以繼續使用所有默認實現,只需覆蓋application.properties(或application.yml)中的以下屬性

jasypt:
  encryptor:
    property:
      prefix: "ENC@["
      suffix: "]"

提供自定義EncryptablePropertyResolver

您可以通過提供一個名為encryptablePropertyResolver的EncryptablePropertyResolver類型的Bean來覆蓋默認實現,或者如果您想提供自己的Bean名稱,請覆蓋屬性jasypt.encryptor.property.resolver-Bean並指定您想給Bean的名稱。當提供這個時,您將負責檢測和解密加密的屬性。例子

class MyEncryptablePropertyResolver implements EncryptablePropertyResolver {


    private final PooledPBEStringEncryptor encryptor;

    public MyEncryptablePropertyResolver(char[] password) {
        this.encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPasswordCharArray(password);
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize(1);
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
    }

    @Override
    public String resolvePropertyValue(String value) {
        if (value != null && value.startsWith("{cipher}")) {
            return encryptor.decrypt(value.substring("{cipher}".length()));
        }
        return value;
    }
}

@Bean(name="encryptablePropertyResolver")
EncryptablePropertyResolver encryptablePropertyResolver(@Value("${jasypt.encryptor.password}") String password) {
    return new MyEncryptablePropertyResolver(password.toCharArray());
}

請注意,通過重寫EncryptablePropertyResolver,您對前綴、后綴、EncryptablePropertyDetector和StringEncryptor的任何其他配置或重寫都將停止工作,因為使用它們的是默認解析程序

因為,對加密屬性的檢測和解密是MyEncryptablePropertyResolver內部的

過濾器

在jasypt-spring-boot:2.1.0版本引入了一個過濾器的新特性。

filter允許您確定要考慮哪些屬性或屬性源進行解密。這是,甚至在檢查要搜索或嘗試解密的實際屬性值之前。例如,默認情況下,名稱以jasypt.encryptor開頭的所有屬性都將從檢查中排除。這是為了在配置庫bean時避免在加載時循環依賴。

默認DefaultPropertyFilter

image-20210507112557922

該類的所有屬性都是從JasyptEncryptorConfigurationProperties.PropertyConfigurationProperties.FilterConfigurationProperties類中讀取

該類只配置了以jasypt.encryptor名字開頭的會被排除,其他都是沒有配置的

image-20210507112646430

自定義EncryptablePropertyFilter

您可以通過提供一個名為EncryptablePropertyFilter的EncryptablePropertyFilter類型的Bean來覆蓋默認實現,或者如果您想提供自己的Bean名稱,請覆蓋屬性jasypt.encryptor.property.filter-Bean並指定您想給Bean的名稱。當提供這個時,您將負責檢測您想要考慮解密的屬性和/或屬性源

    class MyEncryptablePropertyFilter implements EncryptablePropertyFilter {
    
        public boolean shouldInclude(PropertySource<?> source, String name) {
            return name.startsWith('encrypted.');
        }
    }
    @Bean(name="encryptablePropertyFilter")
        EncryptablePropertyFilter encryptablePropertyFilter() {
            return new MyEncryptablePropertyFilter();
        }

請注意,要使此機制正常工作,不應提供自定義的EncryptablePropertyResolver,而應使用默認的解析器。如果您提供自定義EncryptablePropertyResolver,那么您將負責檢測和解密屬性的整個過程。

測試

配置:我這里自己注入了一個StringEncryptor,並自定義了MyEncryptablePropertyDetector,沒有使用默認的解密探測器。

/**
 * @author wen.jie
 * @date 2021/5/7 10:30
 */
@Configuration
public class MyConfig {

    @Bean("jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("password");
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        return encryptor;
    }

    @Bean(name = "encryptablePropertyDetector")
    public EncryptablePropertyDetector encryptablePropertyDetector() {
        return new MyEncryptablePropertyDetector();
    }

    private static class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {
        @Override
        public boolean isEncrypted(String value) {
            if (value != null) {
                return value.startsWith("ENC@");
            }
            return false;
        }

        @Override
        public String unwrapEncryptedValue(String value) {
            return value.substring("ENC@".length());
        }
    }
}

測試代碼:

    @Autowired
    @Qualifier("jasyptStringEncryptor")
    StringEncryptor stringEncryptor;

    @Test
    void contextLoads() {
        String wj = stringEncryptor.encrypt("wj");
        System.out.println(wj);
    }

測試結果:

image-20210507121948586

我們只需要在字符串前面加上ENC@,就可以解密:配置yml

my:
  wj: ENC@8rwL/sEZlOr9hI9ifQj6GtjTjLKKFVfj992j6QZKs6ohPN676yvnHr02vycSiwwO

測試:

    @Value("${my.wj}")
    private String myWj;

    @Test
    void test(){
        System.out.println(myWj);
    }

image-20210507122121971


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM