第一次接触jasypt-spring-boot-starter时,我也被它强大的配置加密能力惊艳到了。这个starter能帮我们轻松解决配置文件敏感信息暴露的问题,特别是数据库密码、API密钥这些需要严格保护的数据。
先来看看最基本的用法。在你的Spring Boot项目中引入依赖:
xml复制<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
这里有个坑我踩过:3.x版本和2.x版本在加密算法上有重大变化。如果你用3.x版本但没指定算法,启动时会报错"failed to bind properties"。解决办法很简单,在application.yml中添加:
yaml复制jasypt:
encryptor:
password: your_secret_key
algorithm: PBEWithMD5AndDES
iv-generator-classname: org.jasypt.iv.NoIvGenerator
加密数据库密码的步骤特别实用。假设你的数据库密码是"123456",先用下面这段代码生成加密字符串:
java复制public static void main(String[] args) {
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword("your_secret_key");
String encrypted = textEncryptor.encrypt("123456");
System.out.println(encrypted); // 输出类似:kud5ZnaMJYve284geT0ITw==
}
然后把加密后的字符串放到配置文件中,用ENC()包裹:
yaml复制spring:
datasource:
password: ENC(kud5ZnaMJYve284geT0ITw==)
最后别忘了在启动类上加@EnableEncryptableProperties注解。这样项目启动时,jasypt会自动解密配置项,你的代码拿到的就是解密后的真实密码了。
默认的ENC()前缀后缀用久了会觉得不够灵活。有次项目需要对接第三方系统,他们要求用特定的标记格式,这就得自定义加解密逻辑了。
首先我们得了解jasypt的工作机制。它主要通过两个关键接口工作:
自定义加解密需要实现这两个接口。比如我们要用"ikms()"作为新的标记:
java复制public class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {
private String prefix = "ikms(";
private String suffix = ")";
@Override
public boolean isEncrypted(String property) {
return property != null && property.startsWith(prefix) && property.endsWith(suffix);
}
@Override
public String unwrapEncryptedValue(String property) {
return property.substring(prefix.length(), property.length() - suffix.length());
}
}
然后实现StringEncryptor。这里我用凯撒加密做演示:
java复制public class CustomStringEncryptor implements StringEncryptor {
@Value("${jasypt.encryptor.password}")
private int shift; // 凯撒加密的位移量
@Override
public String encrypt(String message) {
char[] chars = message.toCharArray();
StringBuilder sb = new StringBuilder();
for (char c : chars) {
sb.append((char)(c + shift));
}
return sb.toString();
}
@Override
public String decrypt(String message) {
char[] chars = message.toCharArray();
StringBuilder sb = new StringBuilder();
for (char c : chars) {
sb.append((char)(c - shift));
}
return sb.toString();
}
}
最后把这些组件装配起来:
java复制@Configuration
public class JasyptConfig {
@Bean
public EncryptablePropertyDetector encryptablePropertyDetector() {
return new MyEncryptablePropertyDetector();
}
@Bean
public StringEncryptor stringEncryptor() {
return new CustomStringEncryptor();
}
}
现在配置文件中可以这样写:
yaml复制spring:
datasource:
password: ikms(uvwx)
这种自定义方式特别适合需要兼容老系统的情况。我曾经遇到过一个项目,需要同时支持三种不同的加密格式,就是通过扩展EncryptablePropertyDetector实现的。
当多个项目都需要相同的加解密逻辑时,最好的办法是打包成Starter。下面分享我开发数据解密Starter的经验。
首先创建自动配置类:
java复制@Configuration
@EnableConfigurationProperties(DataDecryptProperties.class)
public class DataDecryptAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataDecryptService dataDecryptService(DataDecryptProperties properties) {
return new DataDecryptService(properties);
}
@Bean
public EncryptablePropertyDetector encryptablePropertyDetector() {
return new CustomPropertyDetector("AIDSREN(", ")");
}
@Bean
@Primary
public StringEncryptor stringEncryptor(DataDecryptService service) {
return new RemoteStringEncryptor(service);
}
}
配置属性类用来接收Starter的配置项:
java复制@ConfigurationProperties(prefix = "data.decrypt")
public class DataDecryptProperties {
private String remoteUrl;
private int defaultKey;
// getters & setters
}
核心的解密服务类:
java复制public class RemoteStringEncryptor implements StringEncryptor {
private final DataDecryptService service;
public RemoteStringEncryptor(DataDecryptService service) {
this.service = service;
}
@Override
public String encrypt(String message) {
return message; // 不实现加密
}
@Override
public String decrypt(String message) {
if(message.contains("::")) {
// 远程获取密钥
String[] parts = message.split("::");
return service.getFromRemote(parts[0], parts[1]);
}
return service.decryptLocally(message);
}
}
最后在resources/META-INF下创建spring.factories:
code复制org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.DataDecryptAutoConfiguration
使用方只需要引入Starter依赖,然后在配置文件中:
yaml复制data:
decrypt:
remote-url: http://your-kms-service
default-key: 123456
spring:
datasource:
password: AIDSREN(remote_key::encrypted_value)
这个Starter的设计亮点在于:
在实际项目中使用jasypt时,会遇到各种边界情况。这里分享几个典型问题的解决方案。
多环境配置处理
不同环境应该使用不同的加密密钥。我推荐这样组织配置:
yaml复制# application-dev.yml
jasypt:
encryptor:
password: dev_key
# application-prod.yml
jasypt:
encryptor:
password: prod_key
与Spring Cloud Config配合使用
当使用配置中心时,需要在bootstrap.yml中配置:
yaml复制spring:
cloud:
config:
server:
encrypt:
enabled: true
fail-on-error: false
性能优化技巧
大量加密配置会影响启动速度。可以通过这些方式优化:
常见错误排查
安全最佳实践
我曾经遇到过一个棘手问题:在Kubernetes环境中,环境变量注入会破坏加密字符串的格式。解决方案是使用Base64编码后再注入:
yaml复制env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
然后在代码中解码:
java复制@Value("${DB_PASSWORD}")
private String dbPassword;
@PostConstruct
public void init() {
String realPassword = new String(Base64.getDecoder().decode(dbPassword));
// 使用realPassword
}