1. 前景
在使用 spring boot时,通常很多信息都是在application.yml中直接明文配置的,比如数据库链接信息, redis 链接信息等等。但是这样是不安全的。
所以需要对敏感数据进行加密,这样防止密码泄露
Jasypt这个库为我们解决了这个问题,实现了springboot配置的自定加密加密
推荐:SpringBoot2全套教程下载地址 想巩固springboot知识的可以学习一下
2. 简单使用
源码对应地址:
2.1 引入依赖
<properties> | |
< maven .compiler.source>11</maven.compiler.source> | |
<maven.compiler.target></maven.compiler.target> | |
</properties> | |
<dependencyManagement> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-dependencies</artifactId> | |
<version>.4.0</version> | |
<type>pom</type> | |
<scope>import</scope> | |
</dependency> | |
</dependencies> | |
</dependencyManagement> | |
<dependencies> | |
<!-- web 和 测试 --> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-web</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
</dependency> | |
<dependency> | |
<groupId> junit </groupId> | |
<artifactId>junit</artifactId> | |
<scope>test</scope> | |
</dependency> | |
<!-- jdbc --> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-jdbc</artifactId> | |
</dependency> | |
<dependency> | |
<groupId> mysql </groupId> | |
<artifactId>mysql-connector-java</artifactId> | |
</dependency> | |
<!-- jasypt 加密 --> | |
<dependency> | |
<groupId>com.github.ulisesbocchio</groupId> | |
<artifactId>jasypt-spring-boot-starter</artifactId> | |
<version>.0.3</version> | |
</dependency> | |
<dependency> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
</dependency> | |
</dependencies> |
2.2 配置application信息
jasypt配置
jasypt: | |
encryptor: | |
# 加密算法 | |
algorithm: PBEWITHHMACSHAANDAES_256 | |
# 加密使用的盐 | |
password: jaspyt_password |
2.3 加密解密测试
/** | |
* @author HLH | |
* @description: 加密解密测试 | |
*/ | |
public class JasyptTest { | |
private StringEncryptor stringEncryptor; | |
/** | |
* 加密解密测试 | |
*/ | |
public void jasyptTest() { | |
// 加密 | |
System.out.println(stringEncryptor.encrypt(" root ")); // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg | |
// 解密 | |
System.out.println(stringEncryptor.decrypt("JSrINYeIBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg")); // root | |
} | |
/** | |
* 手动测试 | |
*/ | |
public void test() { | |
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); | |
SimpleStringPBEConfig config = new SimpleStringPBEConfig(); | |
config.setPassword("jaspyt_password"); | |
config.setAlgorithm("PBEWITHHMACSHAANDAES_256"); | |
config.setKeyObtentionIterations(""); | |
config.setPoolSize(""); | |
config.setProviderName("SunJCE"); | |
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); | |
config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator"); | |
config.setStringOutputType("base"); | |
encryptor.setConfig(config); | |
System.out.println(encryptor.encrypt("root")); // JSrINYeIBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg | |
} | |
} |
3. 使用Jasypt加密后的 字符串 代替数据库密码
3.1 使用加密类进行加密
密码 root 加密之后 XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
/** | |
* 数据库密码加密 | |
*/@Test | |
public void encryptPasswored() { | |
// 加密 | |
System.out.println(stringEncryptor.encrypt("root")); // XjYnpGdJGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1 | |
// 解密 | |
System.out.println(stringEncryptor.decrypt("XjYnpGdJGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1")); // root | |
} |
3.2 替换数据库配置
spring: | |
DataSource : | |
driver-class-name: com.mysql.cj.jdbc.Driver | |
url: jdbc:mysql://.168.10.31/mp | |
username: root | |
# 使用ENC()包裹,标识为加密之后的,否则无法解密,会报错 | |
password: ENC(RH69h1aEgJ3EDPLXAVQ5CxZJWtl8EvqIJUtlATRt6om4w46/J+blu2JAvkR7Yvp) |
3.3 测试
private DataSource dataSource; | |
/** | |
* 测试加密之后的数据源使用是否正常 | |
* 查看是否能正常获取链接 | |
*/ | |
public void datasourceTest() throws SQL Exception { | |
Connection connection = dataSource.getConnection(); | |
System.out.println(connection); // HikariProxyConnection@ wrapping com.mysql.cj.jdbc.ConnectionImpl@48904d5a | |
connection.close(); | |
} |
4. Jasypt配置详解
所有配置都在 JasyptEncryptorConfigurationProperties 类中定义,我们只需要在yml中配置属性,即可达到重写的目的
Jasypt使用 StringEncryptor 来解密属性。如果Spring上下文中找不到自定义的 StringEncryptor ,就会自动创建一个,可以通过以下属性进行配置
唯一需要的属性是加密的盐,其余的可以使用默认值。虽然所有这些属性都可以在属性文件中生命,但加密所使用的盐不应该存储在属性文件中,而是应该通过系统属性、命令行参数或者环境变量传递,只要他的名称是 jasypt.encryptor.password ,它就可以工作。
倒数第二个属性 jasypt.encryptor.proxyPropertySources 用于只是jasypt spring boot如何拦截属性值进行解密。默认值false使用 PropertySource 、 EnumerablePropertySource 和 MapPropertySource 的自定义包装器实现。当为true时,拦截机制将在每个特定的 PropertySource 实现上使用 CGLib 代理。在某些必须保留原始 PropertySource 类型的场景中,这可能很有用。
5. 自定义加密
默认情况下, Bean 容器会配置 LazyJasyptSringEncryptor
5.1 官方配置
官方配置的Bean都是在 EncryptablePropertyResolverConfiguration 中进行注入的
@ bean ( | |
name = {"lazyJasyptStringEncryptor"} | |
) | |
public StringEncryptor stringEncryptor(EnvCopy envCopy, BeanFactory bf) { | |
String customEncryptorBeanName = envCopy.get().resolveRequiredPlaceholders(ENCRYPTOR_BEAN_PLACEHOLDER); | |
boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.bean"); | |
return new DefaultLazyEncryptor(envCopy.get(), customEncryptorBeanName, isCustom, bf); | |
} |
5.2 自定义加密
可以在Spring上下文中共自定义自己的 StringEncryptor Bean ,默认的加密程序将被忽略
注意
自定义Bean的名称必须为 jasyptStringEncryptor,否则解密不生效
自定义注入bean
/** | |
* 加入 StringEncryptor 加密解密类 | |
* beanName 必须为 jasyptStringEncryptor 才能是自定义的生效 | |
* configProps 为jasypt框架中读取的配置类,就不用自己读取了 | |
*/ | |
public StringEncryptor jasyptStringEncryptor(Singleton<JasyptEncryptorConfigurationProperties> configProps) { | |
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); | |
JasyptEncryptorConfigurationProperties jasyptProperties = configProps.get(); | |
SimpleStringPBEConfig config = new SimpleStringPBEConfig(); | |
config.setPassword(jasyptProperties.getPassword()); | |
config.setAlgorithm(jasyptProperties.getAlgorithm()); | |
config.setKeyObtentionIterations(jasyptProperties.getKeyObtentionIterations()); | |
config.setPoolSize(jasyptProperties.getPoolSize()); | |
config.setProviderName(jasyptProperties.getProviderName()); | |
config.setSaltGeneratorClassName(jasyptProperties.getSaltGeneratorClassname()); | |
config.setIvGeneratorClassName(jasyptProperties.getIvGeneratorClassname()); | |
config.setStringOutputType(jasyptProperties.getStringOutputType()); | |
encryptor.setConfig(config); | |
return encryptor; | |
} |
6. 自定义属性探测器
属性探测器为判断一个属性值是否为加密后的字符串,并且截取真实字符串
6.1 官方处理流程
6.1.2 注入
在 EncryptablePropertyResolverConfiguration 类中
public EncryptablePropertyDetector encryptablePropertyDetector(EnvCopy envCopy, BeanFactory bf) { | |
String customDetectorBeanName = envCopy.get().resolveRequiredPlaceholders(DETECTOR_BEAN_PLACEHOLDER); | |
boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.property.detector-bean"); | |
return new DefaultLazyPropertyDetector(envCopy.get(), customDetectorBeanName, isCustom, bf); | |
} |
6.1.2 DefaultLazyPropertyDetector
默认实现是 DefaultLazyPropertyDetector ,具体代码是
public class DefaultLazyPropertyDetector implements EncryptablePropertyDetector { | |
// 属性探测器 | |
private Singleton<EncryptablePropertyDetector> singleton; | |
public DefaultLazyPropertyDetector(ConfigurableEnvironment environment, String customDetectorBeanName, boolean isCustom, BeanFactory bf) { | |
singleton = new Singleton<>(() -> | |
Optional.of(customDetectorBeanName) | |
.filter(bf::containsBean) | |
.map(name -> (EncryptablePropertyDetector) bf.getBean(name)) | |
.map(tap(bean -> log.info("Found Custom Detector Bean {} with name: {}", bean, customDetectorBeanName))) | |
.orElseGet(() -> { | |
if(isCustom) { | |
throw new Illegal State Exception(String.format("Property Detector custom Bean not found with name '%s'", customDetectorBeanName)); | |
} | |
log.info("Property Detector custom Bean not found with name '{}'. Initializing Default Property Detector", customDetectorBeanName); | |
return createDefault(environment); | |
})); | |
} | |
public DefaultLazyPropertyDetector(ConfigurableEnvironment environment) { | |
// 创建一个属性探测器 | |
singleton = new Singleton<>(() -> createDefault(environment)); | |
} | |
private DefaultPropertyDetector createDefault(ConfigurableEnvironment environment) { | |
// 读取所有的属性 | |
JasyptEncryptorConfigurationProperties props = JasyptEncryptorConfigurationProperties.bindConfigProps(environment); | |
// 创建一个默认的属性探测器,读取配置文件中的前缀和后缀 | |
return new DefaultPropertyDetector(props.getProperty().getPrefix(), props.getProperty().getSuffix()); | |
} | |
/** | |
* 是否为解密格式字符串 | |
*/ | |
public boolean isEncrypted(String property) { | |
return singleton.get().isEncrypted(property); | |
} | |
/** | |
* 获取真是的加密后的字符串 | |
*/ | |
public String unwrapEncryptedValue(String property) { | |
return singleton.get().unwrapEncryptedValue(property); | |
} | |
} |
在其中是创建了一个 DefaultPropertyDetector 对象
6.1.3 DefaultPropertyDetector
public class DefaultPropertyDetector implements EncryptablePropertyDetector { | |
// 默认前缀和后缀 | |
private String prefix = "ENC("; | |
private String suffix = ")"; | |
public DefaultPropertyDetector() { | |
} | |
public DefaultPropertyDetector(String prefix, String suffix) { | |
Assert.notNull(prefix, "Prefix can't be null"); | |
Assert.notNull(suffix, "Suffix can't be null"); | |
this.prefix = prefix; | |
this.suffix = suffix; | |
} | |
public boolean isEncrypted(String property) { | |
if (property == null) { | |
return false; | |
} | |
final String trimmedValue = property.trim(); | |
return (trimmedValue.startsWith(prefix) && | |
trimmedValue.endsWith(suffix)); | |
} | |
// 去掉前缀和后缀 | |
public String unwrapEncryptedValue(String property) { | |
return property.substring( | |
prefix.length(), | |
(property.length() - suffix.length())); | |
} | |
} |
6.2 自定义规则探测器
两种方式自定义
- 提供一个名为 encryptablePropertyDetector 的 EncryptablePropertyDetector 类型的Bean来覆盖默认的实现
- 如果提供的bean名称不为 encryptablePropertyDetector ,可以通过修改yml中的属性 jasypt.encryptor.property.detector-Bean 为自己的bean的名称。
方式
- 要么自定义类
- 要么修改yml中的前缀和后缀
6.2.1 自定义属性探测器,加入容器
/** | |
* 自定义属性探测器 | |
* beanName为 encryptablePropertyDetector | |
*/ (name = "encryptablePropertyDetector") | |
public EncryptablePropertyDetector encryptablePropertyDetector() { | |
return new MyEncryptablePropertyDetector(); | |
} | |
/** | |
* @author HLH | |
* @description: 自定义的属性探测器 | |
* @email@163.com | |
* @date : Created in/8/19 20:01 | |
*/public class MyEncryptablePropertyDetector implements EncryptablePropertyDetector { | |
/** | |
* 是否为可以解密的字符串 | |
* @param value 全部的字符串 | |
* @return 是否是解密的字符串,true,是,false,否 | |
*/ | |
public boolean isEncrypted(String value) { | |
if (value != null) { | |
return value.startsWith("ENC@"); // 自定义规则为 ENC@开头 | |
} | |
return false; | |
} | |
/** | |
* 截取到除了标识之后的值 | |
* @param value 带前缀 | |
* @return string 去掉标识符的字符串 | |
*/ | |
public String unwrapEncryptedValue(String value) { | |
return value.substring("ENC@".length()); // 截取ENC@之后的字符串 | |
} | |
} |
yml中的配置
jasypt: | |
encryptor: | |
# 加密算法 | |
algorithm: PBEWITHHMACSHAANDAES_256 | |
# 加密使用的盐 | |
password: jaspyt_password | |
property: | |
# 修改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用 | |
# prefix: ENC_( | |
# suffix: ) | |
# 自定义的属性探测器,如果这个是自定义的,那么上述的前缀后缀不生效 | |
detector-bean: encryptablePropertyDetector |
6.2.2 修改yml中的配置
spring: | |
datasource: | |
driver-class-name: com.mysql.cj.jdbc.Driver | |
url: jdbc:mysql://.168.10.31/mp | |
username: root | |
# 使用ENC()包裹,标识为加密之后的,否则无法解密,会报错 | |
# 自定义规则之后,使用ENC@开头 | |
password: ENC@JSrINYeIBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg |
7. 自定义规则的前缀和后缀
在上述说明中,在 DefaultLazyPropertyDetector 中是默认是通过配置文件中的规则进行匹配的。默认规则是以ENC(开头,以)结尾,可以复写配置来自定义前缀和后缀
上面第6条是自定义了属性探测器,包括了定义规则和过滤字符串
如果只是想自定义前缀和后缀,那么可以直接修改yml中的配置来修改自定义的前缀和后缀
jasypt: | |
encryptor: | |
# 加密算法 | |
algorithm: PBEWITHHMACSHAANDAES_256 | |
# 加密使用的盐 | |
password: jaspyt_password | |
property: | |
# 修改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用 | |
prefix: ENC( | |
suffix: ) |
8. 直接自定义解密规则
上述6和7自定义了解密字符串的规则和解密字符串的过滤,但是真正的解析处理还是Jasypt框架来负责的。我们也可以直接自定义解密的一系列流程。
8.1 官方处理流程
8.1.1 官方的注入
在 EncryptablePropertyResolverConfiguration 类中
( | |
name = {"lazyEncryptablePropertyResolver"} | |
) | |
public EncryptablePropertyResolver encryptablePropertyResolver("lazyEncryptablePropertyDetector") EncryptablePropertyDetector propertyDetector, ("lazyJasyptStringEncryptor") StringEncryptor encryptor, BeanFactory bf, EnvCopy envCopy, ConfigurableEnvironment environment) { ( | |
String customResolverBeanName = envCopy.get().resolveRequiredPlaceholders(RESOLVER_BEAN_PLACEHOLDER); | |
boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.property.resolver-bean"); | |
return new DefaultLazyPropertyResolver(propertyDetector, encryptor, customResolverBeanName, isCustom, bf, environment); | |
} |
默认注入的是 DefaultLazyPropertyResolver 但是在其中创建的是 EncryptablePropertyResolver 对象
8.1.2 EncryptablePropertyResolver
- 官方默认是通过 EncryptablePropertyResolver 接口来处理解析字符串的
public interface EncryptablePropertyResolver { | |
/** | |
* 处理所有属性的解密处理 | |
* 如果为检测到加密规则,那么返回实际为相同的字符创 | |
* | |
* @param value 属性值 | |
* @return 如果值未加密,返回原值,如果加密,返回加密之后的值 | |
*/ String resolvePropertyValue(String value); | |
} |
- 其真实性使用的实现类是 DefaultPropertyResolver 用来真正处理解析。就是通过调用上文中的 StringEncryptor 处理解密,使用 EncryptablePropertyDetector 定义的解密字符串规则定义是否为加密的字符串
public class DefaultPropertyResolver implements EncryptablePropertyResolver { | |
private final Environment environment; | |
// 默认的或者自定义的StringEncryptor,用来解密 | |
private StringEncryptor encryptor; | |
// 默认的或者自定义的EncryptablePropertyDetector,用来定义是否为加密的字符串 | |
private EncryptablePropertyDetector detector; | |
public DefaultPropertyResolver(StringEncryptor encryptor, Environment environment) { | |
this(encryptor, new DefaultPropertyDetector(), environment); | |
} | |
public DefaultPropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector, Environment environment) { | |
this.environment = environment; | |
Assert.notNull(encryptor, "String encryptor can't be null"); | |
Assert.notNull(detector, "Encryptable Property detector can't be null"); | |
this.encryptor = encryptor; | |
this.detector = detector; | |
} | |
public String resolvePropertyValue(String value) { | |
return Optional.ofNullable(value) | |
.map(environment::resolvePlaceholders) | |
.filter(detector::isEncrypted) // 如果经过属性探测器确认的,才继续 | |
.map(resolvedValue -> { | |
try { | |
String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 过滤加密规则后的字符串 | |
String resolvedProperty = environment.resolvePlaceholders(unwrappedProperty); | |
return encryptor.decrypt(resolvedProperty); // 解密 | |
} catch (EncryptionOperationNotPossibleException e) { | |
throw new DecryptionException("Unable to decrypt: " + value + ". Decryption of Properties failed, make sure encryption/decryption " + | |
"passwords match", e); | |
} | |
}) | |
.orElse(value); | |
} | |
} |
8.2 自定义的解密逻辑
编写自己的解密逻辑类
加入spring容器,命名为 encryptablePropertyResolver ,或者通过yml方式配置自定义bean名称
"encryptablePropertyResolver") | (|
public EncryptablePropertyResolver encryptablePropertyResolver( | |
StringEncryptor jasyptStringEncryptor, EncryptablePropertyDetector encryptablePropertyDetector) { | |
return new MyEncryptablePropertyResolver(jasyptStringEncryptor, encryptablePropertyDetector); | |
} | |
/** | |
* @author HLH | |
* @description: 直接自定义解密规则 | |
* @email@163.com | |
* @date : Created in/8/21 21:22 | |
*/public class MyEncryptablePropertyResolver implements EncryptablePropertyResolver { | |
// 处理解密 | |
private final StringEncryptor encryptor; | |
// 属性探测器 | |
private final EncryptablePropertyDetector detector; | |
public MyEncryptablePropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector) { | |
this.encryptor = encryptor; | |
this.detector = detector; | |
} | |
/** | |
* 处理真正的解密逻辑 | |
* @param value 原始值 | |
* @return 如果值未加密,返回原值,如果加密,返回加密之后的值 | |
*/ | |
public String resolvePropertyValue(String value) { | |
return Optional.ofNullable(value) | |
.filter(detector::isEncrypted) // 如果经过属性探测器确认的,才继续 | |
.map(resolvedValue -> { | |
try { | |
String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 过滤加密规则后的字符串 | |
return encryptor.decrypt(unwrappedProperty); // 解密 | |
} catch (EncryptionOperationNotPossibleException e) { | |
throw new DecryptionException("Unable to decrypt: " + value + ". Decryption of Properties failed, make sure encryption/decryption " + | |
"passwords match", e); | |
} | |
}) | |
.orElse(value); | |
} | |
} |
yml配置
jasypt: | |
encryptor: | |
# 加密算法 | |
algorithm: PBEWITHHMACSHAANDAES_256 | |
# 加密使用的盐 | |
password: jaspyt_password | |
property: | |
# 修改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用 | |
# prefix: ENC_( | |
# suffix: ) | |
# 自定义的属性探测器,如果这个是自定义的,那么上述的前缀后缀不生效 | |
detector-bean: encryptablePropertyDetector | |
# 自定义解密逻辑类 如果配置了,默认的解析器将不工作 | |
resolver-bean: encryptablePropertyResolver |
9. 自定义过滤器
在Jasypt-spring-boot中,引入了过滤器
过滤器filter允许过滤某些属性,不进行解密。默认情况下, jasypt.encryptor 开头的所有属性都会将从检查项中排除掉。这是为了配置Bean,在加载时循环依赖
9.1 默认处理流程
9.1.1 官方的注入
在 EncryptablePropertyResolverConfiguration 类中
public EncryptablePropertyFilter encryptablePropertyFilter(EnvCopy envCopy, ConfigurableBeanFactory bf) { | |
String customFilterBeanName = envCopy.get().resolveRequiredPlaceholders(FILTER_BEAN_PLACEHOLDER); | |
boolean isCustom = envCopy.get().containsProperty("jasypt.encryptor.property.filter-bean"); | |
return new DefaultLazyPropertyFilter(envCopy.get(), customFilterBeanName, isCustom, bf); | |
} |
于上面的逻辑一样,在 DefaultLazyPropertyFilter 中其实是新建了一个 EncryptablePropertyFilter 对象,默认实现类是 DefaultPropertyFilter
9.1.2 DefaultPropertyFilter
public class DefaultPropertyFilter implements EncryptablePropertyFilter { | |
// 过滤的和包含的,优先读取配置文件的 | |
private final List<String> includeSourceNames; | |
private final List<String> excludeSourceNames; | |
private final List<String> includePropertyNames; | |
private final List<String> excludePropertyNames; | |
public DefaultPropertyFilter() { | |
includeSourceNames = null; | |
includePropertyNames = null; | |
excludeSourceNames = null; | |
excludePropertyNames = null; | |
} | |
public DefaultPropertyFilter(List<String> includeSourceNames, List<String> excludeSourceNames, List<String> includePropertyNames, List<String> excludePropertyNames) { | |
this.includeSourceNames = includeSourceNames; | |
this.excludeSourceNames = excludeSourceNames; | |
this.includePropertyNames = includePropertyNames; | |
this.excludePropertyNames = excludePropertyNames; | |
} | |
// 是否拦截 | |
public boolean shouldInclude(PropertySource<?> source, String name) { | |
// 如果上述四个都没有配置,那么全部放行 | |
if (isIncludeAll()) { | |
return true; | |
} | |
// 如果是不包含的,返回false,就过滤掉了 | |
if (isMatch(source.getName(), excludeSourceNames) || isMatch(name, excludePropertyNames)) { | |
return false; | |
} | |
// 如果是包含的,就放行 | |
return isIncludeUnset() || isMatch(source.getName(), includeSourceNames) || isMatch(name, includePropertyNames); | |
} | |
private boolean isIncludeAll() { | |
return isIncludeUnset() && isExcludeUnset(); | |
} | |
private boolean isIncludeUnset() { | |
return isEmpty(includeSourceNames) && isEmpty(includePropertyNames); | |
} | |
private boolean isExcludeUnset() { | |
return isEmpty(excludeSourceNames) && isEmpty(excludePropertyNames); | |
} | |
private boolean isEmpty(List<String> patterns) { | |
return patterns == null || patterns.isEmpty(); | |
} | |
// 传递的配置其实是正则,进行正则匹配 | |
private boolean isMatch(String name, List<String> patterns) { | |
return name != null && !isEmpty(patterns) && patterns.stream().anyMatch(name::matches); | |
} | |
} |
9.2 自定义过滤器
方式
- 要么自定义过滤器
- 要么修改 jasypt.encryptor.property.include-names 或者 jasypt.encryptor.property.exclude-names 配置拦截和放行的资源key
自定义过滤器类
加入spring容器,命名为 encryptablePropertyFilter
/** | |
* 自定义的属性拦截器 | |
* @param configProps Jasypt官方读取的配置集合 | |
* @return 自定义属性拦截器 | |
*/ (name="encryptablePropertyFilter") | |
public EncryptablePropertyFilter encryptablePropertyFilter( | |
Singleton<JasyptEncryptorConfigurationProperties> configProps) { | |
return new MyEncryptablePropertyFilter(configProps.get()); | |
} | |
/** | |
* @author HLH | |
* @description: 自定义的属性过滤器 | |
* @email@163.com | |
* @date : Created in/8/22 13:37 | |
*/public class MyEncryptablePropertyFilter implements EncryptablePropertyFilter { | |
/** jasypt 的所有配置*/ JasyptEncryptorConfigurationProperties jasyptProperties; | |
public MyEncryptablePropertyFilter(JasyptEncryptorConfigurationProperties jasyptProperties) { | |
this.jasyptProperties = jasyptProperties; | |
} | |
public boolean shouldInclude(PropertySource<?> source, String name) { | |
List<String> excludeNames = jasyptProperties.getProperty().getFilter().getExcludeNames(); | |
List<String> includeNames = jasyptProperties.getProperty().getFilter().getIncludeNames(); | |
if (CollectionUtils.isEmpty(includeNames) && CollectionUtils.isEmpty(excludeNames)) { | |
return true; | |
} | |
if (isMatch(source.getName(), excludeNames) || isMatch(source.getName(), excludeNames)) { | |
return false; | |
} | |
return CollectionUtils.isEmpty(includeNames) || | |
isMatch(source.getName(), includeNames) || | |
isMatch(name, includeNames); | |
} | |
/** | |
* 正则判断,如果满足,返回true,如果不满足,返回false | |
* @param name 配置的key | |
* @param patterns 正则列表 | |
* @return 如果满足,返回true,如果不满足,返回false | |
*/ private boolean isMatch(String name, List<String> patterns) { | |
return name != null && !CollectionUtils.isEmpty(patterns) && patterns.stream().anyMatch(name::matches); | |
} | |
} |
yml配置
jasypt: | |
encryptor: | |
# 加密算法 | |
algorithm: PBEWITHHMACSHAANDAES_256 | |
# 加密使用的盐 | |
password: jaspyt_password | |
property: | |
# 修改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用 | |
# prefix: ENC_( | |
# suffix: ) | |
# 自定义的属性探测器,如果这个是自定义的,那么上述的前缀后缀不生效 | |
detector-bean: encryptablePropertyDetector | |
# 自定义解密逻辑类 如果配置了,默认的解析器将不工作 | |
resolver-bean: encryptablePropertyResolver | |
# 过滤器的bean | |
filter-bean: encryptablePropertyFilter | |
# 过滤器配置,正则 | |
filter: | |
# 默认包含的 | |
include-names: | |
# 默认拦截的,默认拦截jasypt.encryptor的配置 | |
exclude-names: | |
- ^jasypt.encryptor.* |
10. 使用mvn插件加密解密
使用代码的方式比较不方便,还需要编码实现,如果不想编码,简单的进行加密解密,就可以使用maven的插件,使用mvn命令进行加密解密
10.1 引入Jasypt的maven插件
<build> | |
<plugins> | |
<!-- Jasypt 的maven插件 --> | |
<plugin> | |
<groupId>com.github.ulisesbocchio</groupId> | |
<artifactId>jasypt-maven-plugin</artifactId> | |
<version>.0.2</version> | |
</plugin> | |
</plugins> | |
</build> |
10.2 加密
使用 jasypt-maven-plugin 插件加密明文密码:(如果配置项是默认值,可以不指定)
mvn jasypt:encrypt-value -Djasypt.encryptor.password="jaspyt_password" -Djasypt.plugin.value="root" -Djasypt.encryptor.algorithm="PBEWITHHMACSHAANDAES_256"
- jasypt.encryptor.password 是秘钥,尽量复杂!不能放在代码和配置文件里面!不能泄漏
- jasypt.plugin.value 是要加密的明文密码
- jasypt.encryptor.algorithm 默认加密算法是 PBEWITHHMACSHA512ANDAES_256 ,需要有JCE( Java Cryptography Extension )支持,如果不想安装JCE,可以使用 PBEWithMD5AndDES 算法。windows下的jdk自带
进入项目所在的目录,输入命令,成功加密
10.3 解密
使用 jasypt-maven-plugin 插件解密密文密码:(如果配置项是默认值,可以不指定)
mvn jasypt:decrypt-value -Djasypt.encryptor.password="jaspyt_password" -Djasypt.plugin.value="pqspkvVfBcKoEltxP9MilGGRo8EE506mDWAuTFIKePDXMeArta13bT6Hl8QqVlC" -Djasypt.encryptor.algorithm="PBEWITHHMACSHA512ANDAES_256"
- jasypt.encryptor.password 是秘钥,尽量复杂!不能放在代码和配置文件里面!不能泄漏
- jasypt.plugin.value 是要加密的明文密码,有ENC()包裹或者不包裹都可以
- jasypt.encryptor.algorithm 默认加密算法是 PBEWITHHMACSHA512ANDAES_256 ,需要有JCE( Java Cryptography Extension )支持,如果不想安装JCE,可以使用 PBEWithMD5AndDES 算法。windows下的jdk自带
进入项目所在的目录,输入命令,成功加密