springboot實(shí)現(xiàn)配置文件關(guān)鍵信息加解密
前言
在項目配置文件中常常會配置如數(shù)據(jù)庫連接信息、redis連接信息,而連接密碼明文配置在配置文件中會很不安全,所以就會將密碼信息加密后放在配置文件中,在啟動項目時自動解密轉(zhuǎn)換成明文后進(jìn)行連接,防止密碼泄露。
方案
1、實(shí)現(xiàn) EnvironmentPostProcessor 接口
2、引入 jasypt-spring-boot-starter 依賴
實(shí)踐
1、第一種方案
EnvironmentPostProcessor 是 Spring Boot 提供的一個接口,用于在 Spring Boot 的 Environment 初始化完成后對其進(jìn)行進(jìn)一步的處理。它允許你在 Spring Boot 的配置加載階段動態(tài)修改或增強(qiáng) Environment 的內(nèi)容,例如添加額外的配置源、修改屬性值等。 ### 作用和用途
EnvironmentPostProcessor 的主要作用是在 Spring Boot 的啟動過程中,對 Environment 對象進(jìn)行擴(kuò)展或修改。它通常用于以下場景:
- 動態(tài)添加配置源:例如,從遠(yuǎn)程配置中心(如 Spring Cloud Config Server、Consul 等)加載配置。
- 修改或覆蓋配置屬性:例如,根據(jù)環(huán)境變量或命令行參數(shù)動態(tài)調(diào)整某些配置值。
- 解析加密的配置屬性:例如,解密配置文件中加密的敏感信息。
- 添加自定義的配置解析邏輯:例如,支持自定義的配置文件格式或解析規(guī)則。
使用方法
實(shí)現(xiàn) EnvironmentPostProcessor 接口,并將自定義實(shí)現(xiàn)類注冊到springboot中
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
/**
* 自定義EnvironmentPostProcessor,在spring啟動前將遍歷配置文件中是否有加密的值,將加密的值按自定義解密工具進(jìn)行解密
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DecryptEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
environment.getPropertySources().forEach(propertySource -> {
if (propertySource instanceof MapPropertySource) {
MapPropertySource mapSource = (MapPropertySource) propertySource;
Map<String, Object> originalSource = mapSource.getSource();
// 創(chuàng)建新的可修改 Map 副本
Map<String, Object> decryptedSource = new HashMap<>(originalSource);
// 遍歷并解密值
decryptedSource.replaceAll((key, value) -> {
if (value instanceof String) {
String strValue = (String) value;
if (strValue.startsWith("ENC(") && strValue.endsWith(")")) {
String encryptedContent = strValue.substring(4, strValue.length() - 1);
return AESEncryptionUtils.decrypt(encryptedContent);
}
}
return value;
});
// 用解密后的 Map 替換原 PropertySource
environment.getPropertySources().replace(
mapSource.getName(),
new MapPropertySource(mapSource.getName(), decryptedSource)
);
}
});
}
}
注冊 EnvironmentPostProcessor 實(shí)現(xiàn)類
在 META-INF/spring.factories 文件中注冊你的 EnvironmentPostProcessor。
org.springframework.boot.env.EnvironmentPostProcessor=\ com.example.DecryptEnvironmentPostProcessor
自定義加解密工具類
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.security.SecureRandom;
public class AESEncryptionUtils {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; // 使用 CBC 模式 + PKCS5 填充
private static final String SECRET_KEY = "oJ51lypwUNzBIFXO"; // 密鑰環(huán)境變量名稱
/**
* 加密明文
* @param plaintext 待加密的明文
* @return 格式為 "Base64(IV):Base64(密文)" 的字符串
*/
public static String encrypt(String plaintext) {
try {
// 生成隨機(jī) IV
byte[] ivBytes = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
// 初始化加密器
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
// 執(zhí)行加密
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// 組合 IV 和密文,用 Base64 編碼
String ivBase64 = Base64.getEncoder().encodeToString(ivBytes);
String encryptedBase64 = Base64.getEncoder().encodeToString(encryptedBytes);
return ivBase64 + ":" + encryptedBase64;
} catch (Exception e) {
throw new RuntimeException("加密失敗", e);
}
}
/**
* 解密密文
* @param encryptedText 格式為 "Base64(IV):Base64(密文)" 的字符串
* @return 解密后的明文
*/
public static String decrypt(String encryptedText) {
try {
// 拆分 IV 和密文
String[] parts = encryptedText.split(":");
if (parts.length != 2) {
throw new IllegalArgumentException("無效的加密格式");
}
byte[] ivBytes = Base64.getDecoder().decode(parts[0]);
byte[] encryptedBytes = Base64.getDecoder().decode(parts[1]);
// 初始化解密器
IvParameterSpec iv = new IvParameterSpec(ivBytes);
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
// 執(zhí)行解密
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("解密失敗", e);
}
}
}
2、第二種方案
引入依賴
在項目的 pom.xml 文件中添加以下依賴:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
配置 jasypt 信息
jasypt:
encryptor:
password: encryption-key
algorithm: PBEWithMD5AndDES
iv-generator-classname: org.jasypt.iv.NoIvGenerator
密碼加密
從 Jasypt 官方網(wǎng)站 或 Maven 中央倉庫下載 jasypt-1.9.3.jar。
使用 Jasypt 的命令行工具對配置信息進(jìn)行加密。例如,加密數(shù)據(jù)庫密碼:
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="123456" password=encryption-key algorithm=PBEWithMD5AndDES
上述命令會輸出一個加密后的字符串,例如:

在配置文件中配置加密后的字符串:
spring:
datasource:
password: ENC(pxaWXichlG6mranljAUiZQ==)
在應(yīng)用啟動時,jasypt 會使用密鑰解密 ENC() 中的內(nèi)容,并將其值注入到對應(yīng)的配置屬性中。
jasypt 加解密工具類
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
/**
* jasypt 解密工具類
*/
public class EncryptionUtil {
public static String encrypt(String input, String password) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword(password);
return encryptor.encrypt(input);
}
public static String decrypt(String encryptedValue, String password) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword(password);
return encryptor.decrypt(encryptedValue);
}
}
補(bǔ)充
jasypt 密鑰配置到配置文件中其實(shí)也不太安全,更安全的做法是將密鑰配置到環(huán)境變量中或設(shè)置在啟動命令中
export JASYPT_ENCRYPTOR_PASSWORD=your-encryption-key
java -jar your-application.jar --jasypt.encryptor.password=your-encryption-key
到此這篇關(guān)于springboot實(shí)現(xiàn)配置文件關(guān)鍵信息加解密的文章就介紹到這了,更多相關(guān)springboot配置文件信息加解密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Springboot不能自動提交數(shù)據(jù)庫連接問題
在使用SSM框架開發(fā)時,若在同一Service內(nèi)部方法間互相調(diào)用,直接使用this關(guān)鍵字會導(dǎo)致事務(wù)管理失效,從而引發(fā)如數(shù)據(jù)庫連接不足等問題,原因是通過this調(diào)用不會經(jīng)過Spring的代理,因此不會自動進(jìn)行事務(wù)處理2024-09-09
java如何將int數(shù)組轉(zhuǎn)化為Integer數(shù)組
這篇文章主要介紹了java如何將int數(shù)組轉(zhuǎn)化為Integer數(shù)組,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
@TransactionalEventListener的使用和實(shí)現(xiàn)原理分析
這篇文章主要介紹了@TransactionalEventListener的使用和實(shí)現(xiàn)原理分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

