首先创建两个注解,一个是写在方法上的注解,表明哪些方法是需要加解密操作的,另一个注解是写在实体类上的字段上(自定义的vo和dto也可以加上注释),表明这个实体类的这个字段需要加解密操作。
1.方法注解
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface EnCodeMethod {
}
2.字段注解
@Inherited
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface EnCodeField {
}
然后创建字段加解密切面
@Order(Ordered.HIGHEST_PRECEDENCE)
@Aspect
@Component
public class asdasd {
Logger log = LoggerFactory.getLogger(this.getClass());
@Pointcut("@annotation(com.ny.common.annotation.EnCodeMethod)")
public void annotationPointCut() {
}
@Around("annotationPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Exception {
Object responseObj = new Object();
try {
Object requestObj = joinPoint.getArgs()[0];
handleEncrypt(requestObj);
responseObj = joinPoint.proceed();
handleDecrypt(responseObj);
} catch (NoSuchMethodException e) {
e.printStackTrace();
log.error("SecureFieldAop处理出现异常{}", e);
throw new RuntimeException("加解密服务异常");
} catch (Throwable throwable) {
throwable.printStackTrace();
log.error("SecureFieldAop处理出现异常{}", throwable);
throw new RuntimeException("加解密服务异常");
}
return responseObj;
}
/**
* 处理加密
*
* @param requestObj
*/
private void handleEncrypt(Object requestObj) throws Exception {
// 加密用的字段,是否需要看实际业务需求
Integer decryptIndex = 1;
if (Objects.isNull(requestObj)) {
return;
}
//获取传入参数的字段list
Field[] fields = getAllField(requestObj);
for (Field field : fields) {
//获取参数中加过注解的字段
boolean hasSecureField = field.isAnnotationPresent(EnCodeField.class);
//判断有没有加过注解的字段
if (hasSecureField) {
field.setAccessible(true);
String plaintextValue;
String encryptValue = null;
if (field.get(requestObj) != null) {
plaintextValue = (String) field.get(requestObj);
//如果有,进行加密操作,然后替换成加密之后的值
encryptValue = encyptEcb(decryptIndex, plaintextValue);
field.set(requestObj, encryptValue);
}
}
}
}
/**
* 处理解密
*
* @param responseObj
*/
private Object handleDecrypt(Object responseObj) throws Exception {
Integer decryptIndex = 1;
if (Objects.isNull(responseObj)) {
return null;
}
//获取返回值的字段
Field[] fields = getAllField(responseObj);
for (Field field : fields) {
//获取加了注解的字段
boolean hasSecureField = field.isAnnotationPresent(EnCodeField.class);
if (hasSecureField) {
field.setAccessible(true);
String encryptValue = (String) field.get(responseObj);
//加密字段可能为空,先做判断
if (!EmptyUtil.isEmpty(encryptValue)) {
//解密
String plaintextValue = decryptEcb(decryptIndex, encryptValue);
field.set(responseObj, plaintextValue);
}
}
}
return responseObj;
}
private Field[] getAllField(Object obj) {
ArrayList fieldList = new ArrayList();
Field[] dFields = obj.getClass().getDeclaredFields();
if (null != dFields && dFields.length > 0) {
fieldList.addAll(Arrays.asList(dFields));
}
//因为业务需求中定义的类可能会直接基础实体类,所以需要把父级中的字段也加上
Class superClass = obj.getClass().getSuperclass();
if (superClass != Object.class) {
Field[] superFields = superClass.getDeclaredFields();
if (null != superFields && superFields.length > 0) {
for (Field field : superFields) {
fieldList.add(field);
}
}
}
Field[] result = new Field[fieldList.size()];
fieldList.toArray(result);
return result;
}
//加密操作,根据实际需求
public String encyptEcb(int keySize, String paramStr) throws Exception {
// 加密操作 TODO
// 根据实际需求加密字段后返回加密字段
return paramStr;
}
//解密操作,根据实际需求
public String decryptEcb(int keySize, String paramStr) throws Exception {
// 解密操作 TODO
// 根据实际需求解密字段后返回解密字段
return paramStr;
}
}
然后实际的业务中在需要的加解密方法体上加上@EnCodeMethod,需要加解密的方法体上加上@EnCodeField即可。
这个切面的操作是把requestObj(传入参数)加密,然后responseObj(返回参数)解密,是一体的。
版权声明:本文为weixin_44229535原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。