package com.monkeylessey.framework.aspect; import com.monkeylessey.annotation.Cipher; import com.monkeylessey.annotation.CipherField; import com.monkeylessey.framework.service.cipher.CipherService; import com.monkeylessey.response.Result; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Objects; @Aspect @Component public class AESAspectHandler { private final CipherService cipherService; public AESAspectHandler(@Qualifier("AESCipherService") CipherService cipherService) { this.cipherService = cipherService; } @Pointcut(value = "execution(* com.monkeylessey.controller.*.*(..,@com.monkeylessey.annotation.Cipher (*),..))") public void point() {} @Pointcut(value = "@annotation(com.monkeylessey.annotation.Cipher)") public void returnPoint() {} @AfterReturning(value = "returnPoint()", returning = "result") public void afterReturn(Object result) throws Exception { if (result.getClass() == Result.class) { Result res = (Result) result; Object data = res.get(Result.DATA); Class dataClass = data.getClass(); Field[] fields = dataClass.getDeclaredFields(); for (Field field : fields) { this.iterationCipherTargetField(false, data, dataClass, field); } } } /** * 必须使用@Around才能处理直接用String作为参数的接口 * @throws Throwable */ @Around(value = "point()") public void around(ProceedingJoinPoint joinPoint) throws Throwable { Object[] args = joinPoint.getArgs(); if (CollectionUtils.isEmpty(Arrays.asList(args))) { return; } MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); // 二维数组:第几个参数;参数上的注解 Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < parameterAnnotations.length; i++) { for (Annotation annotation : parameterAnnotations[i]) { if (annotation instanceof Cipher) { Object arg = args[i]; Class argClass = arg.getClass(); // 检查注解不能作用在Object类型上 this.checkAnnotationOnObject(argClass); // 如果注解作用于String,直接解密 if (argClass == String.class) { String decrypt = cipherService.decode((String) arg); args[i] = decrypt; continue; } // 获取目标对象的所有属性 Field[] fields = argClass.getDeclaredFields(); // 遍历,找到添加了CipherField注解的String类型属性 for (Field field : fields) { this.iterationCipherTargetField(true, arg, argClass, field); } } } } // 执行目标接口 joinPoint.proceed(args); } /** * 迭代对象 解密、加密 String字符串 * * @param arg 接口参数 * @param argClass 接口参数类型 * @param field 接口参数对象的属性 * @throws Exception */ public void iterationCipherTargetField(boolean decode, Object arg, Class argClass, Field field) throws Exception { if (Objects.isNull(arg)) { return; } CipherField annotation = field.getAnnotation(CipherField.class); if (Objects.isNull(annotation)) { return; } Class fieldClass = field.getType(); this.checkAnnotationOnObject(fieldClass); // 未开启解码,则无操作 if (decode && ! annotation.needDecode()) { return; } // 未开启编码,则无操作 if (! decode && ! annotation.needEncode()) { return; } if (fieldClass == String.class) { // String类型直接解密 this.cipherByReflection(decode, arg, argClass, field); } else { // 对象类型,需要判断对象的属性是否有CipherField注解的字符串,如果属性还是对象则继续深入遍历 Field[] childObjectFields = fieldClass.getDeclaredFields(); for (Field childObjectField : childObjectFields) { this.iterationCipherTargetField(decode, getValueByReflection(arg, field), fieldClass, childObjectField); } } } /** * 通过反射修改密文为明文 * @param decode 是否解密 * @param arg * @param argClass * @param field * @throws Exception */ public void cipherByReflection(boolean decode, Object arg, Class argClass, Field field) throws Exception { String fieldName = field.getName(); Method[] methods = argClass.getDeclaredMethods(); Method get = null; // 声明get方法 Method set = null; // 声明set方法 // 遍历目标对象的所有方法,主要是拿到目标属性的get、set方法 for (Method method : methods) { if (method.getName().equals(this.getMethodByFiledName("set", fieldName))) { set = method; } if (method.getName().equals(this.getMethodByFiledName("get", fieldName))) { get = method; } } // 必须要定义set、get方法,否则无法通过反射将密文修改为明文 if (Objects.isNull(set)) { throw new RuntimeException("请为需要解密的字段添加【set】方法"); } if (Objects.isNull(get)) { throw new RuntimeException("请为需要解密的字段添加【get】方法"); } if (decode) { // 解密 set.invoke(arg, cipherService.decode((String) get.invoke(arg))); } else { // 加密 set.invoke(arg, cipherService.encode((String) get.invoke(arg))); } } /** * 主要是获取,属性为对象的值,用于深度遍历 * @param arg 持有这个属性的对象 * @param field * @return * @throws InvocationTargetException * @throws IllegalAccessException */ public Object getValueByReflection(Object arg, Field field) throws InvocationTargetException, IllegalAccessException { Method[] methods = arg.getClass().getDeclaredMethods(); for (Method method : methods) { if (method.getName().equals(this.getMethodByFiledName("get", field.getName()))) { return method.invoke(arg); } } return null; } /** * 检查注解不能作用在Object类型上 * @param target */ public void checkAnnotationOnObject(Class target) { if (target == Object.class) { throw new RuntimeException("CipherField、CipherField注解不能作用在Object类型上"); } } /** * 获取方法名,属性名首字母大写 * * @param prefix * @param fieldName * @return */ public String getMethodByFiledName(String prefix, String fieldName) { String firstWord = fieldName.substring(0,1).toUpperCase(); String method = prefix + firstWord + fieldName.substring(1); return method; } }