根据业务需求,要求多部分字段,进行加解密,想到实现方式,就是通过自定义的注解+AOP来实现
首先新建一个注解,注意ElementType.FIELD类型,说明这个注解只能作用在字段上
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedEncrypt {
}
在新建一个切面类
@Aspect
@Component
public class EncryptionAspect {
@Resource
private EncryptionImpl encryptionService;
//定义切点
@Pointcut("within(com.bosssoft..*.*impl.*) && execution(* *(..))")
public void pointCut(){}
@Around("pointCut()")
public Object encryptDecrypt(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 获取方法参数
Object[] args = joinPoint.getArgs();
Object entity = args[0];
// 加密前
encryptFieldsBeforeSave(entity);
// 执行方法
Object result = joinPoint.proceed(args);
// 解密后
if (result != null) {
decryptFieldsAfterQuery((Object) result);
}
return result;
}
private void encryptFieldsBeforeSave(Object entity) throws IllegalAccessException {
Class<?> clazz = entity.getClass();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(NeedEncrypt.class)) {
field.setAccessible(true);
String value = (String) field.get(entity);
if (value != null) {
String encryptedValue = encryptionService.encrypt(value);
field.set(entity, encryptedValue);
}
}
}
}
private void decryptFieldsAfterQuery(Object entity) throws IllegalAccessException {
Class<?> clazz = entity.getClass();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(NeedEncrypt.class)) {
field.setAccessible(true);
String value = (String) field.get(entity);
if (value != null) {
String decryptedValue = encryptionService.decrypt(value);
field.set(entity, decryptedValue);
}
}
}
}
}
这个类中定义了切面,包含所有的实现类,以及实现类中所有的方法
下一步创建这个切面类的实现类,用来实现一些方法,比如:具体的加解密算法
本加密算法采用的是AES
@Component
public class EncryptionImpl {
private static final String SECRET_KEY = "your_secret_key";
private static final String ALGORITHM = "AES";
public String encrypt(String valueToEncrypt) {
try {
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedValue = cipher.doFinal(valueToEncrypt.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedValue);
} catch (Exception e) {
throw new RuntimeException("Encryption failed", e);
}
}
public String decrypt(String encryptedValue) {
try {
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decodedValue = Base64.getDecoder().decode(encryptedValue);
byte[] decryptedValue = cipher.doFinal(decodedValue);
return new String(decryptedValue, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("Decryption failed", e);
}
}
}
注意的AES算法的密钥长度, 必须是 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)
示例:
新增数据:
查询数据: