SpringBoot 配置文件這樣加密,才足夠安全!
回復(fù)架構(gòu)師獲取資源
大家好,我是你們的朋友架構(gòu)君,一個會寫代碼吟詩的架構(gòu)師。
'javajgs.com';
原文:
blog.csdn.net/HLH_2021/article/details/119854365
1. 前景
在使用Springboot時,通常很多信息都是在application.yml中直接明文配置的,比如數(shù)據(jù)庫鏈接信息,redis鏈接信息等等。但是這樣是不安全的。
所以需要對敏感數(shù)據(jù)進(jìn)行加密,這樣防止密碼泄露
Jasypt這個庫為我們解決了這個問題,實(shí)現(xiàn)了springboot配置的自定加密加密
2. 簡單使用
源碼對應(yīng)地址:
http://gitlab.sea-clouds.cn/csdn/spring-boot-csdn/-/tree/master/05-spring-boot-jasypt
2.1 引入依賴
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.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>3.0.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2.2 配置application信息
jasypt配置
jasypt:
encryptor:
# 加密算法
algorithm: PBEWITHHMACSHA512ANDAES_256
# 加密使用的鹽
password: jaspyt_password
2.3 加密解密測試
/**
* @author HLH
* @description: 加密解密測試
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class JasyptTest {
@Autowired
private StringEncryptor stringEncryptor;
/**
* 加密解密測試
*/
@Test
public void jasyptTest() {
// 加密
System.out.println(stringEncryptor.encrypt("root")); // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
// 解密
System.out.println(stringEncryptor.decrypt("JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg")); // root
}
/**
* 手動測試
*/
@Test
public void test() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword("jaspyt_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);
System.out.println(encryptor.encrypt("root")); // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
}
}
3. 使用Jasypt加密后的字符串代替數(shù)據(jù)庫密碼
3.1 使用加密類進(jìn)行加密
密碼 root 加密之后 XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
/**
* 數(shù)據(jù)庫密碼加密
*/
@Test
public void encryptPasswored() {
// 加密
System.out.println(stringEncryptor.encrypt("root")); // XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
// 解密
System.out.println(stringEncryptor.decrypt("XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1")); // root
}
3.2 替換數(shù)據(jù)庫配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.31/mp
username: root
# 使用ENC()包裹,標(biāo)識為加密之后的,否則無法解密,會報錯
password: ENC(R2H69h1aEgJ3EDPLXAVQ5CxZJWtl8EvqIJUtlATRt6om4w46/J+blu2JAvkR7Yvp)
3.3 測試
@Autowired
private DataSource dataSource;
/**
* 測試加密之后的數(shù)據(jù)源使用是否正常
* 查看是否能正常獲取鏈接
*/
@Test
public void datasourceTest() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println(connection); // HikariProxyConnection@1487059223 wrapping com.mysql.cj.jdbc.ConnectionImpl@48904d5a
connection.close();
}
4. Jasypt配置詳解
所有配置都在JasyptEncryptorConfigurationProperties類中定義,我們只需要在yml中配置屬性,即可達(dá)到重寫的目的
Jasypt使用StringEncryptor來解密屬性。如果Spring上下文中找不到自定義的StringEncryptor,就會自動創(chuàng)建一個,可以通過以下屬性進(jìn)行配置

唯一需要的屬性是加密的鹽,其余的可以使用默認(rèn)值。雖然所有這些屬性都可以在屬性文件中生命,但加密所使用的鹽不應(yīng)該存儲在屬性文件中,而是應(yīng)該通過系統(tǒng)屬性、命令行參數(shù)或者環(huán)境變量傳遞,只要他的名稱是jasypt.encryptor.password,它就可以工作。
倒數(shù)第二個屬性jasypt.encryptor.proxyPropertySources用于只是jasypt spring boot如何攔截屬性值進(jìn)行解密。默認(rèn)值false使用PropertySource、EnumerablePropertySource和MapPropertySource的自定義包裝器實(shí)現(xiàn)。當(dāng)為true時,攔截機(jī)制將在每個特定的PropertySource實(shí)現(xiàn)上使用CGLib代理。在某些必須保留原始PropertySource類型的場景中,這可能很有用。
5. 自定義加密
默認(rèn)情況下,bean容器會配置LazyJasyptSringEncryptor
5.1 官方配置
官方配置的Bean都是在EncryptablePropertyResolverConfiguration中進(jìn)行注入的
@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,默認(rèn)的加密程序?qū)⒈缓雎?/span>
注意
自定義Bean的名稱必須為
jasyptStringEncryptor,否則解密不生效
自定義注入bean
/**
* 加入 StringEncryptor 加密解密類
* beanName 必須為 jasyptStringEncryptor 才能是自定義的生效
* configProps 為jasypt框架中讀取的配置類,就不用自己讀取了
*/
@Bean("jasyptStringEncryptor")
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. 自定義屬性探測器
屬性探測器為判斷一個屬性值是否為加密后的字符串,并且截取真實(shí)字符串
6.1 官方處理流程
6.1.2 注入
在EncryptablePropertyResolverConfiguration類中
@Bean(
name = {"lazyEncryptablePropertyDetector"}
)
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
默認(rèn)實(shí)現(xiàn)是DefaultLazyPropertyDetector,具體代碼是
@Slf4j
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 IllegalStateException(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) {
// 創(chuàng)建一個屬性探測器
singleton = new Singleton<>(() -> createDefault(environment));
}
private DefaultPropertyDetector createDefault(ConfigurableEnvironment environment) {
// 讀取所有的屬性
JasyptEncryptorConfigurationProperties props = JasyptEncryptorConfigurationProperties.bindConfigProps(environment);
// 創(chuàng)建一個默認(rèn)的屬性探測器,讀取配置文件中的前綴和后綴
return new DefaultPropertyDetector(props.getProperty().getPrefix(), props.getProperty().getSuffix());
}
/**
* 是否為解密格式字符串
*/
@Override
public boolean isEncrypted(String property) {
return singleton.get().isEncrypted(property);
}
/**
* 獲取真是的加密后的字符串
*/
@Override
public String unwrapEncryptedValue(String property) {
return singleton.get().unwrapEncryptedValue(property);
}
}
在其中是創(chuàng)建了一個DefaultPropertyDetector對象
6.1.3 DefaultPropertyDetector
public class DefaultPropertyDetector implements EncryptablePropertyDetector {
// 默認(rèn)前綴和后綴
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;
}
@Override
public boolean isEncrypted(String property) {
if (property == null) {
return false;
}
final String trimmedValue = property.trim();
return (trimmedValue.startsWith(prefix) &&
trimmedValue.endsWith(suffix));
}
// 去掉前綴和后綴
@Override
public String unwrapEncryptedValue(String property) {
return property.substring(
prefix.length(),
(property.length() - suffix.length()));
}
}
6.2 自定義規(guī)則探測器
兩種方式自定義
提供一個名為 encryptablePropertyDetector的EncryptablePropertyDetector類型的Bean來覆蓋默認(rèn)的實(shí)現(xiàn)如果提供的bean名稱不為 encryptablePropertyDetector,可以通過修改yml中的屬性jasypt.encryptor.property.detector-Bean為自己的bean的名稱。
方式
要么自定義類 要么修改yml中的前綴和后綴
6.2.1 自定義屬性探測器,加入容器
/**
* 自定義屬性探測器
* beanName為 encryptablePropertyDetector
*/
@Bean(name = "encryptablePropertyDetector")
public EncryptablePropertyDetector encryptablePropertyDetector() {
return new MyEncryptablePropertyDetector();
}
/**
* @author HLH
* @description: 自定義的屬性探測器
* @email [email protected]
* @date : Created in 2021/8/19 20:01
*/
public class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {
/**
* 是否為可以解密的字符串
* @param value 全部的字符串
* @return 是否是解密的字符串,true,是,false,否
*/
@Override
public boolean isEncrypted(String value) {
if (value != null) {
return value.startsWith("ENC@"); // 自定義規(guī)則為 ENC@開頭
}
return false;
}
/**
* 截取到除了標(biāo)識之后的值
* @param value 帶前綴
* @return string 去掉標(biāo)識符的字符串
*/
@Override
public String unwrapEncryptedValue(String value) {
return value.substring("ENC@".length()); // 截取ENC@之后的字符串
}
}
yml中的配置
jasypt:
encryptor:
# 加密算法
algorithm: PBEWITHHMACSHA512ANDAES_256
# 加密使用的鹽
password: jaspyt_password
property:
# 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
# prefix: ENC_(
# suffix: )
# 自定義的屬性探測器,如果這個是自定義的,那么上述的前綴后綴不生效
detector-bean: encryptablePropertyDetector
6.2.2 修改yml中的配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.31/mp
username: root
# 使用ENC()包裹,標(biāo)識為加密之后的,否則無法解密,會報錯
# 自定義規(guī)則之后,使用ENC@開頭
password: ENC@JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
7. 自定義規(guī)則的前綴和后綴
在上述說明中,在DefaultLazyPropertyDetector中是默認(rèn)是通過配置文件中的規(guī)則進(jìn)行匹配的。默認(rèn)規(guī)則是以ENC(開頭,以)結(jié)尾,可以復(fù)寫配置來自定義前綴和后綴
上面第6條是自定義了屬性探測器,包括了定義規(guī)則和過濾字符串
如果只是想自定義前綴和后綴,那么可以直接修改yml中的配置來修改自定義的前綴和后綴
jasypt:
encryptor:
# 加密算法
algorithm: PBEWITHHMACSHA512ANDAES_256
# 加密使用的鹽
password: jaspyt_password
property:
# 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
prefix: ENC(
suffix: )
8. 直接自定義解密規(guī)則
上述6和7自定義了解密字符串的規(guī)則和解密字符串的過濾,但是真正的解析處理還是Jasypt框架來負(fù)責(zé)的。我們也可以直接自定義解密的一系列流程。
8.1 官方處理流程
8.1.1 官方的注入
在EncryptablePropertyResolverConfiguration類中
@Bean(
name = {"lazyEncryptablePropertyResolver"}
)
public EncryptablePropertyResolver encryptablePropertyResolver(@Qualifier("lazyEncryptablePropertyDetector") EncryptablePropertyDetector propertyDetector, @Qualifier("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);
}
默認(rèn)注入的是DefaultLazyPropertyResolver但是在其中創(chuàng)建的是EncryptablePropertyResolver對象
8.1.2 EncryptablePropertyResolver
官方默認(rèn)是通過 EncryptablePropertyResolver接口來處理解析字符串的
public interface EncryptablePropertyResolver {
/**
* 處理所有屬性的解密處理
* 如果為檢測到加密規(guī)則,那么返回實(shí)際為相同的字符創(chuàng)
*
* @param value 屬性值
* @return 如果值未加密,返回原值,如果加密,返回加密之后的值
*/
String resolvePropertyValue(String value);
}
其真實(shí)性使用的實(shí)現(xiàn)類是 DefaultPropertyResolver用來真正處理解析。就是通過調(diào)用上文中的StringEncryptor處理解密,使用EncryptablePropertyDetector定義的解密字符串規(guī)則定義是否為加密的字符串
public class DefaultPropertyResolver implements EncryptablePropertyResolver {
private final Environment environment;
// 默認(rèn)的或者自定義的StringEncryptor,用來解密
private StringEncryptor encryptor;
// 默認(rèn)的或者自定義的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;
}
@Override
public String resolvePropertyValue(String value) {
return Optional.ofNullable(value)
.map(environment::resolvePlaceholders)
.filter(detector::isEncrypted) // 如果經(jīng)過屬性探測器確認(rèn)的,才繼續(xù)
.map(resolvedValue -> {
try {
String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 過濾加密規(guī)則后的字符串
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名稱
@Bean("encryptablePropertyResolver")
public EncryptablePropertyResolver encryptablePropertyResolver(
StringEncryptor jasyptStringEncryptor, EncryptablePropertyDetector encryptablePropertyDetector) {
return new MyEncryptablePropertyResolver(jasyptStringEncryptor, encryptablePropertyDetector);
}
/**
* @author HLH
* @description: 直接自定義解密規(guī)則
* @email [email protected]
* @date : Created in 2021/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 如果值未加密,返回原值,如果加密,返回加密之后的值
*/
@Override
public String resolvePropertyValue(String value) {
return Optional.ofNullable(value)
.filter(detector::isEncrypted) // 如果經(jīng)過屬性探測器確認(rèn)的,才繼續(xù)
.map(resolvedValue -> {
try {
String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 過濾加密規(guī)則后的字符串
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: PBEWITHHMACSHA512ANDAES_256
# 加密使用的鹽
password: jaspyt_password
property:
# 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
# prefix: ENC_(
# suffix: )
# 自定義的屬性探測器,如果這個是自定義的,那么上述的前綴后綴不生效
detector-bean: encryptablePropertyDetector
# 自定義解密邏輯類 如果配置了,默認(rèn)的解析器將不工作
resolver-bean: encryptablePropertyResolver
9. 自定義過濾器
在Jasypt-spring-boot中,引入了過濾器
過濾器filter允許過濾某些屬性,不進(jìn)行解密。默認(rèn)情況下,jasypt.encryptor開頭的所有屬性都會將從檢查項中排除掉。這是為了配置Bean,在加載時循環(huán)依賴
9.1 默認(rèn)處理流程
9.1.1 官方的注入
在EncryptablePropertyResolverConfiguration類中
@Bean(
name = {"lazyEncryptablePropertyFilter"}
)
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中其實(shí)是新建了一個EncryptablePropertyFilter對象,默認(rèn)實(shí)現(xiàn)類是DefaultPropertyFilter
9.1.2 DefaultPropertyFilter
public class DefaultPropertyFilter implements EncryptablePropertyFilter {
// 過濾的和包含的,優(yōu)先讀取配置文件的
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;
}
// 是否攔截
@Override
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();
}
// 傳遞的配置其實(shí)是正則,進(jìn)行正則匹配
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 自定義屬性攔截器
*/
@Bean(name="encryptablePropertyFilter")
public EncryptablePropertyFilter encryptablePropertyFilter(
Singleton<JasyptEncryptorConfigurationProperties> configProps) {
return new MyEncryptablePropertyFilter(configProps.get());
}
/**
* @author HLH
* @description: 自定義的屬性過濾器
* @email [email protected]
* @date : Created in 2021/8/22 13:37
*/
public class MyEncryptablePropertyFilter implements EncryptablePropertyFilter {
/** jasypt 的所有配置*/
JasyptEncryptorConfigurationProperties jasyptProperties;
public MyEncryptablePropertyFilter(JasyptEncryptorConfigurationProperties jasyptProperties) {
this.jasyptProperties = jasyptProperties;
}
@Override
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: PBEWITHHMACSHA512ANDAES_256
# 加密使用的鹽
password: jaspyt_password
property:
# 修改默認(rèn)的前綴和后綴,如果自定義屬性探測器,那么此項配置不起作用
# prefix: ENC_(
# suffix: )
# 自定義的屬性探測器,如果這個是自定義的,那么上述的前綴后綴不生效
detector-bean: encryptablePropertyDetector
# 自定義解密邏輯類 如果配置了,默認(rèn)的解析器將不工作
resolver-bean: encryptablePropertyResolver
# 過濾器的bean
filter-bean: encryptablePropertyFilter
# 過濾器配置,正則
filter:
# 默認(rèn)包含的
include-names:
# 默認(rèn)攔截的,默認(rèn)攔截jasypt.encryptor的配置
exclude-names:
- ^jasypt\.encryptor\.*
10. 使用mvn插件加密解密
使用代碼的方式比較不方便,還需要編碼實(shí)現(xiàn),如果不想編碼,簡單的進(jìn)行加密解密,就可以使用maven的插件,使用mvn命令進(jìn)行加密解密
10.1 引入Jasypt的maven插件
<build>
<plugins>
<!-- Jasypt 的maven插件 -->
<plugin>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-maven-plugin</artifactId>
<version>3.0.2</version>
</plugin>
</plugins>
</build>
10.2 加密
使用jasypt-maven-plugin插件加密明文密碼:(如果配置項是默認(rèn)值,可以不指定)
mvn jasypt:encrypt-value -Djasypt.encryptor.password="jaspyt_password" -Djasypt.plugin.value="root" -Djasypt.encryptor.algorithm="PBEWITHHMACSHA512ANDAES_256"
jasypt.encryptor.password是秘鑰,盡量復(fù)雜!不能放在代碼和配置文件里面!不能泄漏jasypt.plugin.value是要加密的明文密碼jasypt.encryptor.algorithm默認(rèn)加密算法是PBEWITHHMACSHA512ANDAES_256,需要有JCE(Java Cryptography Extension)支持,如果不想安裝JCE,可以使用PBEWithMD5AndDES算法。windows下的jdk自帶
進(jìn)入項目所在的目錄,輸入命令,成功加密

10.3 解密
使用jasypt-maven-plugin插件解密密文密碼:(如果配置項是默認(rèn)值,可以不指定)
mvn jasypt:decrypt-value -Djasypt.encryptor.password="jaspyt_password" -Djasypt.plugin.value="pqsp6kvVfBcKoEltxP9MilGGRo8EE506mDWAuTFIKePDXMeArta13bT6Hl8QqVlC" -Djasypt.encryptor.algorithm="PBEWITHHMACSHA512ANDAES_256"
jasypt.encryptor.password是秘鑰,盡量復(fù)雜!不能放在代碼和配置文件里面!不能泄漏jasypt.plugin.value是要加密的明文密碼,有ENC()包裹或者不包裹都可以jasypt.encryptor.algorithm默認(rèn)加密算法是PBEWITHHMACSHA512ANDAES_256,需要有JCE(Java Cryptography Extension)支持,如果不想安裝JCE,可以使用PBEWithMD5AndDES算法。windows下的jdk自帶
進(jìn)入項目所在的目錄,輸入命令,成功加密

11. 思維導(dǎo)圖
最后再來一張思維導(dǎo)圖

這些年小編給你分享過的干貨
2.優(yōu)質(zhì)ERP系統(tǒng)帶進(jìn)銷存財務(wù)生產(chǎn)功能(附源碼)
3.優(yōu)質(zhì)SpringBoot帶工作流管理項目(附源碼)
5.SBoot+Vue外賣系統(tǒng)前后端都有(附源碼)

轉(zhuǎn)發(fā)在看就是最大的支持??
