前言
产品提出新的需求,操作数据库数据需要对当前用户进行校验,具有资格的用户才能操作,但是用户数据在其他的平台上,只能通过http请求发送token + caseId获取返回值来校验。
- 为什么使用aop?
- 项目采用restful,使用拦截器+filter这种方式无法解析全部请求中caseId,例如使用@PathVariable注解无法解析。
编写注解
@Target(ElementType.METHOD) // 用在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行
@Documented
public @interface AuthorityCheck {
//注解中使用了元注解时,可以对元注解的值进行重写,并且可用多个不同的别名进行重写(其实就是一和二的结合)
@AliasFor("name")
String value() default "caseId";
@AliasFor("value")
String name() default "caseId";
}
编写切面
@Aspect //定义切面
@Component
public class AuthorityAspect {
// 判断是否开启权限校验
@Value("${authority.open}") // 从配置文件读取
private Boolean open;
// 用户平台地址
@Value("${authority.authorityUrl}")
private String authorityUrl;
//
@Pointcut("@annotation(com.bmsoft.evidence.aop.AuthorityCheck)")
public void annotationPoinCut() {
}
@After("annotationPoinCut()")
public void after(JoinPoint joinPoint) {
}
@Before("annotationPoinCut()")
public void before(JoinPoint joinPoint) {
//判断是否开启
if (!open) {
return;
}
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
// 获取request 拿到token
HttpServletRequest request = sra.getRequest();
String token = request.getHeader("Authorization");
//校验token
if (token == null) {
throw new AppException(ErrorCode.GET_DATA_FAILED, "请求头Authorization为空!");
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取接口全部参数
Object[] args = joinPoint.getArgs();
String[] argNames = signature.getParameterNames();
Method method = signature.getMethod();
AuthorityCheck action = method.getAnnotation(AuthorityCheck.class);
String value = action.value();
List<String> paths = Arrays.asList(value.split("\\."));
if (paths.size() == 0) {
throw new UnknownAnnotationValueException(null, action.value());
}
String firstName = paths.get(0);
String caseId = "";
for (int i = 0; i < argNames.length; i++) {
String argName = argNames[i];
Object arg = args[i];
Class<?> aClass = arg.getClass();
if (argName.equals(firstName)) {
// 判断caseI这个参数实在dto 还是直接就在请求头中
if (paths.size() > 1) {
caseId = takeCaseId(aClass, arg, paths, 1);
} else if (arg instanceof String) {
caseId = (String) arg;
} else {
throw new RuntimeException("caseId字段类型错误");
}
}
}
token = token.replace("bearer ", "");
JSONObject result;
String url = String.format("%s", authorityUrl);
Map<String, Object> checkPost = new HashMap<>();
checkPost.put("ajbs", caseId);
checkPost.put("accessToken", token);
try {
HttpClientResult httpClientResult = ClientHelp.doPost(url, checkPost);
if (httpClientResult.getCode() != 200) {
throw new AppException(ErrorCode.GET_DATA_FAILED, "权限接口调用出错");
}
String content = httpClientResult.getContent();
result = JSON.parseObject(content);
} catch (Exception e) {
throw new AppException(ErrorCode.GET_DATA_FAILED, "获取权限失败");
}
if (result.getInteger("code") != 1000) {
throw new AppException(ErrorCode.GET_DATA_FAILED, "权限接口调用出错");
}
if (!result.getBoolean("data")) {
throw new AppException(ErrorCode.GET_DATA_FAILED, "您不是承办人,无操作权限!");
}
}
// 通过反射找到caseId的值并且返回
private String takeCaseId(Class<?> clazz, Object object, List<String> paths, Integer pathNum) {
if (paths.get(pathNum) == null) {
return null;
}
String s = paths.get(pathNum);
try {
Field field = clazz.getDeclaredField(s);
field.setAccessible(true);
Object o = field.get(object);
if (paths.size() > pathNum + 1) {
return takeCaseId(o.getClass(), o, paths, pathNum + 1);
} else if (o instanceof String) {
String caseId = (String) o;
return caseId;
} else {
throw new RuntimeException("caseId字段类型错误");
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}