1. 前景
在使用Springboot時,通常很多資訊都是在application.yml中直接明文配置的,比如資料庫連結資訊,redis連結資訊等等。但是這樣是不安全的。
是以需要對敏感資料進行加密,這樣防止密碼洩露
Jasypt這個庫為我們解決了這個問題,實作了springboot配置的自定加密加密
2. 簡單使用
源碼對應位址:
gitlab.sea-clouds.cn/csdn/spring…
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加密後的字元串代替資料庫密碼
3.1 使用加密類進行加密
密碼 root 加密之後 XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
/**
* 資料庫密碼加密
*/
@Test
public void encryptPasswored() {
// 加密
System.out.println(stringEncryptor.encrypt("root")); // XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
// 解密
System.out.println(stringEncryptor.decrypt("XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1")); // root
}
複制代碼
3.2 替換資料庫配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.10.31/mp
username: root
# 使用ENC()包裹,辨別為加密之後的,否則無法解密,會報錯
password: ENC(R2H69h1aEgJ3EDPLXAVQ5CxZJWtl8EvqIJUtlATRt6om4w46/J+blu2JAvkR7Yvp)
複制代碼
3.3 測試
@Autowired
private DataSource dataSource;
/**
* 測試加密之後的資料源使用是否正常
* 檢視是否能正常擷取連結
*/
@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中配置屬性,即可達到重寫的目的
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架構中讀取的配置類,就不用自己讀取了
*/
@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. 自定義屬性探測器
屬性探測器為判斷一個屬性值是否為加密後的字元串,并且截取真實字元串
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
預設實作是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) {
// 建立一個屬性探測器
singleton = new Singleton<>(() -> createDefault(environment));
}
private DefaultPropertyDetector createDefault(ConfigurableEnvironment environment) {
// 讀取所有的屬性
JasyptEncryptorConfigurationProperties props = JasyptEncryptorConfigurationProperties.bindConfigProps(environment);
// 建立一個預設的屬性探測器,讀取配置檔案中的字首和字尾
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);
}
}
複制代碼
在其中是建立了一個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;
}
@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 自定義規則探測器
兩種方式自定義
- 提供一個名為encryptablePropertyDetector的EncryptablePropertyDetector類型的Bean來覆寫預設的實作
- 如果提供的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@"); // 自定義規則為 ENC@開頭
}
return false;
}
/**
* 截取到除了辨別之後的值
* @param value 帶字首
* @return string 去掉辨別符的字元串
*/
@Override
public String unwrapEncryptedValue(String value) {
return value.substring("ENC@".length()); // 截取ENC@之後的字元串
}
}
複制代碼
yml中的配置
jasypt:
encryptor:
# 加密算法
algorithm: PBEWITHHMACSHA512ANDAES_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://192.168.10.31/mp
username: root
# 使用ENC()包裹,辨別為加密之後的,否則無法解密,會報錯
# 自定義規則之後,使用ENC@開頭
password: ENC@JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
複制代碼
7. 自定義規則的字首和字尾
在上述說明中,在DefaultLazyPropertyDetector中是預設是通過配置檔案中的規則進行比對的。預設規則是以ENC(開頭,以)結尾,可以複寫配置來自定義字首和字尾
上面第6條是自定義了屬性探測器,包括了定義規則和過濾字元串
如果隻是想自定義字首和字尾,那麼可以直接修改yml中的配置來修改自定義的字首和字尾
jasypt:
encryptor:
# 加密算法
algorithm: PBEWITHHMACSHA512ANDAES_256
# 加密使用的鹽
password: jaspyt_password
property:
# 修改預設的字首和字尾,如果自定義屬性探測器,那麼此項配置不起作用
prefix: ENC(
suffix: )
複制代碼
8. 直接自定義解密規則
上述6和7自定義了解密字元串的規則和解密字元串的過濾,但是真正的解析處理還是Jasypt架構來負責的。我們也可以直接自定義解密的一系列流程。
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);
}
複制代碼
預設注入的是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;
}
@Override
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名稱
@Bean("encryptablePropertyResolver")
public EncryptablePropertyResolver encryptablePropertyResolver(
StringEncryptor jasyptStringEncryptor, EncryptablePropertyDetector encryptablePropertyDetector) {
return new MyEncryptablePropertyResolver(jasyptStringEncryptor, encryptablePropertyDetector);
}
/**
* @author HLH
* @description: 直接自定義解密規則
* @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) // 如果經過屬性探測器确認的,才繼續
.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: PBEWITHHMACSHA512ANDAES_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類中
@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中其實是建立了一個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;
}
// 是否攔截
@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();
}
// 傳遞的配置其實是正則,進行正則比對
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:
# 修改預設的字首和字尾,如果自定義屬性探測器,那麼此項配置不起作用
# 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>3.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="PBEWITHHMACSHA512ANDAES_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="pqsp6kvVfBcKoEltxP9MilGGRo8EE506mDWAuTFIKePDXMeArta13bT6Hl8QqVlC" -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自帶
進入項目所在的目錄,輸入指令,成功加密
11. 思維導圖
最後再來一張思維導圖
來源:blog.csdn.net/HLH_2021/article/details/119854365