整合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部分),则会自动创建一个,可以通过以下属性(系统、属性文件、命令行参数、环境变量等)进行配置:
唯一需要的属性是加密密码,其余的可以使用默认值。虽然所有这些属性都可以在属性文件中声明,但加密程序密码不应该存储在属性文件中,而应该作为系统属性、命令行参数或环境变量传递,只要它的名称是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
该类的所有属性都是从JasyptEncryptorConfigurationProperties.PropertyConfigurationProperties.FilterConfigurationProperties
类中读取
该类只配置了以jasypt.encryptor
名字开头的会被排除,其他都是没有配置的
自定义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);
}
测试结果:
我们只需要在字符串前面加上ENC@,就可以解密:配置yml
my:
wj: ENC@8rwL/sEZlOr9hI9ifQj6GtjTjLKKFVfj992j6QZKs6ohPN676yvnHr02vycSiwwO
测试:
@Value("${my.wj}")
private String myWj;
@Test
void test(){
System.out.println(myWj);
}