SpringBoot配置文件中密碼屬性加密的實現(xiàn)
本文主要介紹了SpringBoot配置文件中的明文密碼如何加密保存,讀取以及對于自定義的加密算法加密的參數(shù)如何保存和讀取。
背景
為了安全的需要,一些重要的信息比如數(shù)據(jù)庫密碼不能明文保存在配置文件中,需要進行加密之后再保存。SpringBoot可以使用jasypt-spring-boot這個組件來為配置屬性提供加密的支持。
集成jasypt-spring-boot到項目中
根據(jù)官方README文檔,可以有三種方式集成jasypt-spring-boot到項目中。
對于SpringBoot項目,直接通過引入jasypt-spring-boot-starter,然后所有的application.properties, application-*.properties, yaml的配置文件中就可以包含加密的屬性。
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.4</version> </dependency>
直接引入jasypt-spring-boot,這時候需要在啟動類上添加一個@EnableEncryptableProperties,然后在配置文件中可以包含有加密的字段屬性。
@SpringBootApplication
@EnableEncryptableProperties
public class Application {
...
}
如果不想要整個Spring的配置文件都啟用加密的字段屬性,還可以自己指定對應加密的配置文件路徑。也需要引入jasypt-spring-boot,同時在啟動類上添加@EncryptablePropertySource注解,設置注解的value屬性為需要讀取的加密配置文件路徑。
@SpringBootApplication
@EncryptablePropertySource({"classpath:encrypted.properties"})
public class Application {
...
}
配置文件配置加密與讀取
現(xiàn)在知道了如何集成jasypt-spring-boot到項目中,下面就介紹一下如何加密明文的密碼,以及需要如何存儲在配置文件中。
首先,需要添加一個maven的插件,這個插件可以幫助我們加密我們需要的明文信息。
<plugin> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-maven-plugin</artifactId> <version>3.0.4</version> </plugin>
之后,執(zhí)行如下的mvn命令,可以在控制臺得到對于的密文。然后將配置文件中明文替換為加密后的密文。
mvn jasypt:encrypt-value -Djasypt.encryptor.password="TKzhc3fz" -Djasypt.plugin.value="123456"
-Djasypt.encryptor.password參數(shù)指定用于加密密碼,我理解這個應該和秘鑰類似。
-Djasypt.plugin.value參數(shù)指定需要加密的明文參數(shù)。
執(zhí)行命令后,可以在控制臺看到加密后的密文,密文默認是用ENC()格式包圍住的,當然這個格式也可以自定義。

也可以通過這個mvn插件解密,執(zhí)行如下命令,可以在控制臺看到解密之后的明文。
mvn jasypt:decrypt-value -Djasypt.encryptor.password="TKzhc3fz" -Djasypt.plugin.value="ENC(Muhq57xdiHA5jJX9pX7zmNz57w4emX2D/XYIXOMEx0LYcTL7RYyadWe2J7GCi9KJ)"

在SpringBoot配置文件中,添加jasypt.encryptor.password屬性,這個值和第二步生成密文的值要一樣,不然解密會失敗。
jasypt:
encryptor:
password: TKzhc3fz # 設置加密的password信息 類似秘鑰?
test:
password: ENC(Muhq57xdiHA5jJX9pX7zmNz57w4emX2D/XYIXOMEx0LYcTL7RYyadWe2J7GCi9KJ) # 測試數(shù)據(jù)
這樣在主程序啟動的時候,通過@Value注解就可以自動解密配置文件中的密文信息了,這樣就完成了明文的加密以及后續(xù)的讀取。
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-muDkBMKU-1643293746249)(/Users/yuanzhihao/Desktop/截屏2022-01-27 下午10.14.26.jpg)]](http://img.jbzj.com/file_images/article/202207/2022072010303630.jpg)
工作原理簡析
參照官方文檔,大概的工作原理如下:
首先,在Spring容器啟動之后,會遍歷配置文件中的所有的配置,然后發(fā)現(xiàn)所有按照jasypt約定規(guī)則加密的屬性,此處就是使用ENC()包圍的參數(shù),這個ENC()前綴和后綴是可以自定義的,下面會講到。
這邊主要是有兩個接口,分別是EncryptablePropertyDetector、EncryptablePropertyResolver,這兩個接口根據(jù)名稱可以看出來一個是發(fā)現(xiàn)器,一個是分解器。
先來看EncryptablePropertyDetector這個接口,這個接口提供了兩個方法,isEncrypted和unwrapEncryptedValue,isEncrypted方法判斷是否是jasypt約定規(guī)則加密的屬性,unwrapEncryptedValue方法會返回去除掉前綴和后綴的真正加密的值,可以看下該接口默認的實現(xiàn)DefaultPropertyDetector:
/**
* Default property detector that detects encrypted property values with the format "$prefix$encrypted_value$suffix"
* Default values are "ENC(" and ")" respectively.
*
* @author Ulises Bocchio
*/
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;
}
// 判斷配置屬性是否是按照jasypt約定規(guī)則加密的屬性
@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()));
}
}
EncryptablePropertyResolver這個接口中只提供了一個方法resolvePropertyValue,這個方法會遍歷配置文件屬性,判斷是否是加密屬性,然后進行解密返回明文。在默認實現(xiàn)DefaultPropertyResolver中,依賴EncryptablePropertyDetector以及StringEncryptor,真正解密的方法是寫在StringEncryptor,這邊具體如何解密就不詳細描述了,有興趣可以自行看下。DefaultPropertyResolver類:
/**
* @author Ulises Bocchio
*/
public class DefaultPropertyResolver implements EncryptablePropertyResolver {
private final Environment environment;
// 加密和解密的實現(xiàn)
private StringEncryptor encryptor;
// jasypt默認發(fā)現(xiàn)器
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) {
// 該方法獲取加密的屬性,然后使用StringEncryptor解密并返回
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 property: " + value + " resolved to: " + resolvedValue + ". Decryption of Properties failed, make sure encryption/decryption " +
"passwords match", e);
}
})
.orElse(value);
}
}
使用自定義的加密算法
如果不想要使用jasypt工具中的加密算法,或者內(nèi)部要求使用某種特定的加密算法,jasypt-spring-boot組件也提供了自定義加解密的實現(xiàn)方式。上面在工作原理簡析中提到了兩個接口EncryptablePropertyDetector、EncryptablePropertyResolver,我們可以通過自己實現(xiàn)這兩個接口的方式,并且指定對應的bean名稱為encryptablePropertyDetector和encryptablePropertyResolver來覆蓋框架提供的默認實現(xiàn),完成加密算法和前綴后綴的自定義。
這邊我就用base64加密算法舉例,實現(xiàn)自定義的加密算法:
自己實現(xiàn)EncryptablePropertyDetector、EncryptablePropertyResolver接口,并且交給Spring管理,設置bean名稱為encryptablePropertyDetector和encryptablePropertyResolver。
重寫接口對應的方法。
@Component("encryptablePropertyDetector")
public class Base64EncryptablePropertyDetector implements EncryptablePropertyDetector {
private static final String PREFIX = "password:";
@Override
public boolean isEncrypted(String property) {
if (property == null) {
return false;
}
return property.startsWith(PREFIX);
}
@Override
public String unwrapEncryptedValue(String property) {
return property.substring(PREFIX.length());
}
}
@Component("encryptablePropertyResolver")
public class Base64EncryptablePropertyResolver implements EncryptablePropertyResolver {
@Autowired
private Base64EncryptablePropertyDetector encryptablePropertyDetector;
@Override
public String resolvePropertyValue(String value) {
return Optional.ofNullable(value)
.filter(encryptablePropertyDetector::isEncrypted)
.map(resolveValue -> {
final String unwrapEncryptedValue = encryptablePropertyDetector.unwrapEncryptedValue(resolveValue);
return new String(Base64.getDecoder().decode(unwrapEncryptedValue),
StandardCharsets.UTF_8);
})
.orElse(value);
}
}
配置文件中的加密屬性使用自定義的前綴和后綴。這邊明文先使用base64加密,之后加上“password:”前綴:
jasypt:
encryptor:
password: TKzhc3fz # 設置加密的password信息 類似秘鑰?
test:
password: password:MTIzNDU2 # 測試數(shù)據(jù)
啟動和讀取。

結語
參考鏈接:https://github.com/ulisesbocchio/jasypt-spring-boot
代碼地址:https://github.com/yzh19961031/SpringCloudDemo
到此這篇關于SpringBoot配置文件中密碼屬性加密的實現(xiàn)的文章就介紹到這了,更多相關SpringBoot 文件密碼屬性加密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
apollo更改配置刷新@ConfigurationProperties配置類
這篇文章主要為大家介紹了apollo更改配置刷新@ConfigurationProperties配置類示例解析,apollo更改配置刷新@ConfigurationProperties配置類2023-04-04
Java中system.exit(0) 和 system.exit(1)區(qū)別
本文主要介紹了Java中system.exit(0) 和 system.exit(1)區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-05-05

