一、项目集成Jasypt完整方案
1. Maven依赖配置
xml
<!-- pom.xml -->
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0</version>
</dependency>
<!-- Jasypt 加密 -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
</dependencies>
2. 配置文件结构
yaml
# bootstrap.yml (或 bootstrap.properties)
# 此文件优先加载,用于Nacos配置
spring:
application:
name: user-service # 微服务名称
profiles:
active: dev # 环境标识
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848 # Nacos地址
file-extension: yaml # 配置文件格式
namespace: ${spring.profiles.active} # 对应环境命名空间
group: DEFAULT_GROUP
extension-configs:
- data-id: jasypt-config.yaml # Jasypt专用配置
group: COMMON_CONFIG
refresh: true
- data-id: datasource-common.yaml # 数据源公共配置
group: COMMON_CONFIG
refresh: true
3. Nacos中的配置内容
jasypt-config.yaml
yaml
# Nacos配置中心中存放
# 数据ID: jasypt-config.yaml
# 分组: COMMON_CONFIG
# Jasypt加密配置
jasypt:
encryptor:
# 加密密码(必须保护)
# 生产环境建议通过环境变量或启动参数传入
password: ${JASYPT_ENCRYPTOR_PASSWORD:mySecretKey123!}
# 加密算法
algorithm: PBEWithMD5AndDES # 可选:PBEWithMD5AndDES, PBEWithSHA1AndDESede, PBEWITHHMACSHA512ANDAES_256
# 密钥获取迭代次数
key-obtention-iterations: 1000
# 盐生成器类名
salt-generator-classname: org.jasypt.salt.RandomSaltGenerator
# 算法提供商(JDK版本相关)
provider-name: SunJCE
# IV(初始化向量)生成器
iv-generator-classname: org.jasypt.iv.RandomIvGenerator
# 输出格式,默认为base64
string-output-type: base64
# 加密前缀和后缀(用于识别加密值)
property:
prefix: "ENC("
suffix: ")"
datasource-common.yaml
yaml
# Nacos配置中心中存放
# 数据ID: datasource-common.yaml
# 分组: COMMON_CONFIG
# 数据源配置(使用Jasypt加密)
spring:
datasource:
# 动态数据库URL(可根据环境变化)
url: jdbc:mysql://${db.host:localhost}:${db.port:3306}/${db.name:testdb}?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: ENC(5yWhYHrJ8A+tskRZWk9ndQ==) # 加密的用户名
password: ENC(JlzqDblbW0quZarZfT3wFjL6J/5A8+FV) # 加密的密码
# Druid连接池配置
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 监控配置
filter:
stat:
enabled: true
log-slow-sql: true
slow-sql-millis: 1000
wall:
enabled: true
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: true
url-pattern: /druid/*
allow: 127.0.0.1
deny: ''
login-username: admin
login-password: ENC(加密后的监控密码)
# 动态数据库配置(可在不同环境覆盖)
db:
host: 10.28.15.36
port: 3306
name: sbh_admin
user-service-dev.yaml(环境特定配置)
yaml
# Nacos配置中心中存放
# 数据ID: user-service-dev.yaml
# 分组: DEFAULT_GROUP
# 微服务特定配置
server:
port: 8081
# Redis配置(加密示例)
spring:
redis:
host: localhost
port: 6379
password: ENC(w6lEwUyJ7zP4K1qL8M9n2Q==) # Redis密码加密
timeout: 3000ms
# 业务配置
user:
service:
max-retry-count: 3
timeout: 5000
api-key: ENC(A1B2C3D4E5F6G7H8I9J0K==) # 第三方API密钥加密
4. 加密工具类
java
package com.example.user.utils;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Jasypt加密解密工具类
*/
@Component
public class JasyptUtil {
@Autowired
private StringEncryptor stringEncryptor;
/**
* 加密方法
* @param plainText 明文
* @return 密文(带ENC()前缀)
*/
public String encrypt(String plainText) {
if (plainText == null || plainText.trim().isEmpty()) {
return plainText;
}
String encrypted = stringEncryptor.encrypt(plainText);
return "ENC(" + encrypted + ")";
}
/**
* 解密方法
* @param encryptedText 密文(可带ENC()前缀)
* @return 明文
*/
public String decrypt(String encryptedText) {
if (encryptedText == null || encryptedText.trim().isEmpty()) {
return encryptedText;
}
// 去除ENC()前缀
if (encryptedText.startsWith("ENC(") && encryptedText.endsWith(")")) {
encryptedText = encryptedText.substring(4, encryptedText.length() - 1);
}
return stringEncryptor.decrypt(encryptedText);
}
/**
* 批量加密(用于初始化配置)
*/
public void batchEncryptDemo() {
String[] plainTexts = {
"root",
"password123",
"myRedisPassword",
"apiSecretKey2024"
};
for (String plainText : plainTexts) {
String encrypted = encrypt(plainText);
System.out.println("明文: " + plainText);
System.out.println("密文: " + encrypted);
System.out.println("解密验证: " + decrypt(encrypted));
System.out.println("---");
}
}
}
5. Spring Boot配置类
java
package com.example.user.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import javax.sql.DataSource;
/**
* 数据源配置类
*/
@Configuration
public class DataSourceConfig {
/**
* 配置Druid数据源
* 注意:@Value注解会自动解密ENC()包裹的值
*/
@Bean
public DataSource dataSource(Environment env) {
// 从环境变量中获取已解密的配置
String url = env.getProperty("spring.datasource.url");
String username = env.getProperty("spring.datasource.username");
String password = env.getProperty("spring.datasource.password");
System.out.println("数据源配置已加载:");
System.out.println("URL: " + url);
System.out.println("用户名: " + username);
// 生产环境不建议打印密码
// System.out.println("密码: " + password);
return DruidDataSourceBuilder.create()
.url(url)
.username(username)
.password(password)
.build();
}
}
6. 启动类增强
java
package com.example.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import com.example.user.utils.JasyptUtil;
import javax.sql.DataSource;
import java.sql.Connection;
@SpringBootApplication
public class UserServiceApplication implements CommandLineRunner {
@Autowired
private Environment env;
@Autowired
private JasyptUtil jasyptUtil;
@Autowired
private DataSource dataSource;
public static void main(String[] args) {
// 方式1:通过环境变量设置加密密码
// System.setProperty("JASYPT_ENCRYPTOR_PASSWORD", "your-secret-key");
// 方式2:通过启动参数设置加密密码
// java -jar user-service.jar --jasypt.encryptor.password=your-secret-key
SpringApplication.run(UserServiceApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// 验证配置解密是否成功
System.out.println("=== Jasypt配置验证 ===");
// 验证数据库连接
try (Connection conn = dataSource.getConnection()) {
System.out.println("✅ 数据库连接成功");
System.out.println("数据库URL: " + env.getProperty("spring.datasource.url"));
System.out.println("数据库用户: " + env.getProperty("spring.datasource.username"));
} catch (Exception e) {
System.err.println("❌ 数据库连接失败: " + e.getMessage());
}
// 验证加密解密功能
String testText = "HelloJasypt";
String encrypted = jasyptUtil.encrypt(testText);
String decrypted = jasyptUtil.decrypt(encrypted);
System.out.println("加密解密测试:");
System.out.println("原文: " + testText);
System.out.println("密文: " + encrypted);
System.out.println("解密: " + decrypted);
System.out.println("测试结果: " + (testText.equals(decrypted) ? "✅ 成功" : "❌ 失败"));
// 显示当前使用的加密算法
System.out.println("当前加密算法: " +
env.getProperty("jasypt.encryptor.algorithm", "默认算法"));
}
}
7. Docker部署配置
dockerfile
# Dockerfile
FROM openjdk:11-jre-slim
# 设置环境变量(用于传递加密密码)
ENV JASYPT_ENCRYPTOR_PASSWORD=""
ENV SPRING_PROFILES_ACTIVE="prod"
# 创建应用目录
RUN mkdir -p /app
WORKDIR /app
# 复制jar包
COPY target/user-service.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", \
"-Djava.security.egd=file:/dev/./urandom", \
"-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", \
"-Djasypt.encryptor.password=${JASYPT_ENCRYPTOR_PASSWORD}", \
"-jar", "app.jar"]
8. Kubernetes部署配置
yaml
# k8s-deployment.yaml
apiVersion: v1
kind: Secret
metadata:
name: jasypt-secret
type: Opaque
data:
# 使用base64编码的加密密码(echo -n "myProdSecret2024!" | base64)
encryptor-password: bXlQcm9kU2VjcmV0MjAyNCE=
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 2
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:1.0.0
ports:
- containerPort: 8080
env:
- name: JASYPT_ENCRYPTOR_PASSWORD
valueFrom:
secretKeyRef:
name: jasypt-secret
key: encryptor-password
- name: SPRING_PROFILES_ACTIVE
value: "prod"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP
9. 命令行工具脚本
bash
#!/bin/bash
# encrypt-tool.sh - Jasypt加密工具脚本
# 配置
JASYPT_ALGORITHM="PBEWithMD5AndDES"
JASYPT_PASSWORD="mySecretKey123!"
JASYPT_ITERATIONS="1000"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 帮助信息
show_help() {
echo "Jasypt加密工具"
echo "使用方法: $0 [选项]"
echo "选项:"
echo " encrypt <明文> 加密文本"
echo " decrypt <密文> 解密文本(可带ENC()前缀)"
echo " file <文件路径> 批量加密文件中的值"
echo " genkey 生成随机加密密钥"
echo " test 测试加密解密功能"
echo " help 显示此帮助信息"
}
# 加密函数
encrypt_text() {
local plaintext="$1"
if [ -z "$plaintext" ]; then
echo -e "${RED}错误: 请输入要加密的文本${NC}"
return 1
fi
# 使用Java加密
ENCRYPTED=$(java -cp ".:jasypt-1.9.3.jar" \
-Djasypt.encryptor.password="$JASYPT_PASSWORD" \
-Djasypt.encryptor.algorithm="$JASYPT_ALGORITHM" \
org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
input="$plaintext" password="$JASYPT_PASSWORD" \
algorithm="$JASYPT_ALGORITHM" \
iterations="$JASYPT_ITERATIONS" | grep "ENC(")
if [ -n "$ENCRYPTED" ]; then
echo -e "${GREEN}加密成功:${NC}"
echo "明文: $plaintext"
echo "密文: $ENCRYPTED"
else
echo -e "${RED}加密失败${NC}"
fi
}
# 生成加密配置
generate_config() {
echo -e "${YELLOW}生成加密配置示例:${NC}"
echo ""
echo "# 数据库配置"
echo "spring.datasource.username=ENC($(java -cp ".:jasypt-1.9.3.jar" \
-Djasypt.encryptor.password="$JASYPT_PASSWORD" \
org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
input="root" password="$JASYPT_PASSWORD" \
algorithm="$JASYPT_ALGORITHM" | grep -o "ENC([^)]*)"))"
echo ""
echo "# Redis配置"
echo "spring.redis.password=ENC($(java -cp ".:jasypt-1.9.3.jar" \
-Djasypt.encryptor.password="$JASYPT_PASSWORD" \
org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
input="redis123" password="$JASYPT_PASSWORD" \
algorithm="$JASYPT_ALGORITHM" | grep -o "ENC([^)]*)"))"
}
# 主函数
main() {
case "$1" in
encrypt)
encrypt_text "$2"
;;
decrypt)
# 解密逻辑类似
;;
genkey)
# 生成16位随机密钥
echo -e "${GREEN}生成的随机密钥:${NC}"
openssl rand -base64 16
;;
test)
echo -e "${YELLOW}测试加密解密...${NC}"
TEST_TEXT="TestPassword@123"
ENCRYPTED=$(encrypt_text "$TEST_TEXT" | grep "密文:" | cut -d' ' -f2)
echo "测试完成"
;;
help|*)
show_help
;;
esac
}
# 执行
main "$@"
10. 多环境密钥管理方案
properties
# 不同环境使用不同的加密密钥
# 开发环境
dev.jasypt.password=dev_secret_2024!
# 测试环境
test.jasypt.password=test_secret_2024!
# 生产环境(从安全存储获取)
prod.jasypt.password=${VAULT:prod/jasypt/password}
# 在启动脚本中指定
#!/bin/bash
# startup.sh
ENV=$1
case $ENV in
"dev")
export JASYPT_ENCRYPTOR_PASSWORD="dev_secret_2024!"
;;
"test")
export JASYPT_ENCRYPTOR_PASSWORD="test_secret_2024!"
;;
"prod")
# 从HashiCorp Vault获取密钥
export JASYPT_ENCRYPTOR_PASSWORD=$(vault read -field=password secret/prod/jasypt)
;;
*)
echo "Unknown environment"
exit 1
;;
esac
java -jar user-service.jar
二、最佳实践建议
1. 安全建议
- 生产环境加密密码不要写在代码或配置文件中
- 使用环境变量或密钥管理服务(如Vault)传递加密密码
- 定期轮换加密密钥
- 不同环境使用不同的加密密钥
2. 微服务架构中的使用
yaml
# 在微服务网关统一管理加密配置
# gateway-service配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- name: JasyptConfigFilter # 自定义过滤器处理加密配置
3. 监控和告警
java
// 监控Jasypt解密状态
@Component
public class JasyptHealthIndicator implements HealthIndicator {
@Autowired
private JasyptUtil jasyptUtil;
@Override
public Health health() {
try {
String test = "health_check";
String encrypted = jasyptUtil.encrypt(test);
String decrypted = jasyptUtil.decrypt(encrypted);
if (test.equals(decrypted)) {
return Health.up()
.withDetail("status", "Jasypt工作正常")
.withDetail("algorithm", "PBEWithMD5AndDES")
.build();
} else {
return Health.down()
.withDetail("error", "加密解密不匹配")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
这套方案提供了从开发到生产全链路的加密配置管理,适合微服务架构下的安全需求。