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

原文地址:https://www.cnblogs.com/wwjj4811/p/14738704.html