零侵入加解密方案:Spring Boot + Jasypt + AOP实现敏感数据自动保护
1. 添加依赖
在pom.xml
中添加Jasypt和AOP依赖:
<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.5</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 配置Jasypt
在application.yml
中配置加密密钥和算法:
jasypt:encryptor:password: your_secret_key # 加密密钥(需保密)algorithm: PBEWithMD5AndDESiv-generator-classname: org.jasypt.iv.NoIvGenerator
3. 实现加解密工具类
import org.jasypt.encryption.StringEncryptor;
import org.springframework.stereotype.Component;@Component
public class EncryptionUtils {private final StringEncryptor encryptor;public EncryptionUtils(StringEncryptor encryptor) {this.encryptor = encryptor;}public String encrypt(String data) {return encryptor.encrypt(data);}public String decrypt(String data) {return encryptor.decrypt(data);}
}
4. 定义自定义注解
import java.lang.annotation.*;@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveField {
}
5. 实现AOP切面处理加解密
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;@Aspect
@Component
public class SensitiveFieldAspect {@Autowiredprivate EncryptionUtils encryptionUtils;// 加密切面:拦截带@Encrypt注解的方法@Around("@annotation(com.yourpackage.Encrypt)")public Object encryptSensitiveFields(ProceedingJoinPoint joinPoint) throws Throwable {Object result = joinPoint.proceed(); // 执行原方法processFields(result, true); // 加密处理return result;}// 解密切面:拦截带@Decrypt注解的方法@Around("@annotation(com.yourpackage.Decrypt)")public Object decryptSensitiveFields(ProceedingJoinPoint joinPoint) throws Throwable {Object[] args = joinPoint.getArgs();for (Object arg : args) {processFields(arg, false); // 解密处理}return joinPoint.proceed(args);}/*** 递归处理字段加解密* @param target 目标对象* @param isEncrypt true=加密, false=解密*/private void processFields(Object target, boolean isEncrypt) {if (target == null) return;Class<?> clazz = target.getClass();for (Field field : clazz.getDeclaredFields()) {try {field.setAccessible(true);Object value = field.get(target);// 递归处理嵌套对象if (value != null && !field.isAnnotationPresent(SensitiveField.class)) {processFields(value, isEncrypt);}// 处理敏感字段if (field.isAnnotationPresent(SensitiveField.class) {if (value instanceof String) {String newValue = isEncrypt ? encryptionUtils.encrypt((String) value) : encryptionUtils.decrypt((String) value);field.set(target, newValue);}}} catch (IllegalAccessException e) {throw new RuntimeException("字段访问失败", e);}}}
}
6. 定义方法级注解
// 加密注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
}// 解密注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
}
7. 在实体类中使用注解
public class User {@SensitiveFieldprivate String phoneNumber;@SensitiveFieldprivate String idCard;// 其他字段和getter/setter
}
8. 在Service层使用加解密
@Service
public class UserService {@Encryptpublic User saveUser(User user) {// 保存前自动加密敏感字段(通过AOP拦截)return userRepository.save(user);}@Decryptpublic User getUserById(Long id) {// 查询后自动解密敏感字段(通过AOP拦截)return userRepository.findById(id).orElse(null);}
}
关键点说明:
敏感字段标记:
在实体字段添加@SensitiveField
,AOP会识别这些字段进行加解密方法级控制:
@Encrypt
:方法返回值中的敏感字段自动加密@Decrypt
:方法参数的敏感字段自动解密
递归处理:
切面支持嵌套对象的递归处理,确保多层结构中的敏感字段都能被处理加解密时机:
加密:数据库保存前(写操作)
解密:数据查询后(读操作)
测试配置:
在测试类中配置加密器:
@SpringBootTest
public class EncryptionTest {@Autowiredprivate StringEncryptor encryptor;@Testvoid testEncryption() {String raw = "13800138000";String encrypted = encryptor.encrypt(raw);String decrypted = encryptor.decrypt(encrypted);System.out.println("原始数据:" + raw);System.out.println("加密结果:" + encrypted);System.out.println("解密结果:" + decrypted);Assertions.assertEquals(raw, decrypted);}
}
注意事项:
密钥安全:
生产环境禁止硬编码密钥,应通过环境变量传入:
-Djasypt.encryptor.password=${SECRET_KEY}
性能考虑:
深度嵌套的大对象可能影响性能,建议控制递归深度
类型适配:
当前实现仅处理String类型,如需其他类型需扩展
集合类型支持:
如需支持List<User>等集合类型,需在切面中增加集合处理逻辑
这种方案实现了敏感字段加解密的自动化和透明化,业务代码无需关注加解密细节,只需通过注解声明即可完成安全数据处理。