前言
有时业务需要对一些敏感字段处理,结合权限系统,对不同请求方的字段权限进行字段控制。本方案是基于AOP方案。
核心代码
-
AuthorityField(需要权限校验的字段标记)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author xionghu
* @date 2023/2/17 10:13
* @desc 需要权限控制的字段标记
*/
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorityField {
String[] value() default "";
}
-
AuthorityFieldAspect(字段权限AOP核心处理类)
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author xionghu
* @date 2023/2/17 10:46
* @desc 字段权限AOP核心处理类
*/
@Slf4j
@Aspect
@Component
public class AuthorityFieldAspect {
private static final String DATA_KEY = "data";
/**
*
*/
@Pointcut("@annotation(com.yqsl.contact.adaptor.web.aop.CheckAuthorityField)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//解密
Object result = handle(joinPoint);
return result;
}
public Object handle(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
Object obj = joinPoint.proceed();
if (obj != null) {
//也可以不对请求返回结果,针对接口返回接口
result = handleJsonData(obj);
}
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
/**
* 注意一般接口返回形式
* {
* "code": 0,
* "msg": "成功",
* "data": {}
* }
*
* @param obj
* @return
* @throws IllegalAccessException
*/
private Object handleJsonData(Object obj) throws IllegalAccessException {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
if (DATA_KEY.equals(field.getName())) {
field.setAccessible(true);
Object fieldObject = field.get(obj);
if (fieldObject instanceof ArrayList) {
handleListObject(fieldObject);
} else {
handleObj(fieldObject);
}
}
}
return obj;
}
/**
* 针对对象类型字段权限校验
*
* @param obj
* @throws IllegalAccessException
*/
private void handleObj(Object obj) throws IllegalAccessException {
List<Field> fields = listAllFields(obj);
for (Field field : fields) {
if (field.getType().equals(List.class)) {
field.setAccessible(true);
Object fieldObject = field.get(obj);
handleListObject(fieldObject);
continue;
}
boolean hasSecureField = field.isAnnotationPresent(AuthorityField.class);
//TODO 调用权限认证接口
if (hasSecureField) {
field.setAccessible(true);
//TODO 结合自己的权限系统处理
// 通过字段权限 不设为null
// 没通过 设为null
field.set(obj, null);
}
}
}
/**
* 获取本类和超类字段
*
* @param obj
*/
private List<Field> listAllFields(Object obj) {
List fieldList = new ArrayList();
Class tmpClass = obj.getClass();
while (tmpClass != null) {
fieldList.addAll(Arrays.asList(tmpClass.getDeclaredFields()));
tmpClass = tmpClass.getSuperclass();
}
return fieldList;
}
/**
* 针对list<实体来> 进行反射、解密
*
* @param obj
* @throws IllegalAccessException
*/
private void handleListObject(Object obj) throws IllegalAccessException {
List<Object> result = new ArrayList<>();
if (obj instanceof ArrayList) {
for (Object o : (List<?>) obj) {
result.add(o);
}
}
for (Object object : result) {
handleObj(object);
}
}
}
-
CheckAuthorityField(需要字段权限校验的接口标记类)
/**
* @author xionghu
* @date 2023/2/17 10:46
* @desc 需要字段权限校验的接口标记
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckAuthorityField {
}
使用示例
-
标记需要权限校验的字段
-
接口开启字段权限认证
-
请求结果