![v2-ab1044070b57c334b63afb59b922fcfc_1440w.jpg?source=172ae18b](http://img-01.proxy.5ce.com/view/image?&type=2&guid=17f47237-e82f-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-ab1044070b57c334b63afb59b922fcfc_1440w.jpg?source=172ae18b)
引言:本文主要通过注解方式进行权限验证
一.什么是注解
注解是一种特殊的Java构造器,它可以用于装饰类,方法,字段,参数,变量,构造函数或包。
二.编写自定义注解
在编写自定义注解的时候,我们首先需要搞清楚几个默认的注解,这几个注解仅仅作用与另一个注解之上。
@Documented
@Documented注解表明这个注解要被javadoc记录。注解默认状态下是不被javadoc记录的。
@Retention
注解表明该注解保留到那个阶段,主要有三个值:
SOURCE —— 这种注解保留在源代码级别,编译时就会被忽略
CLASS —— 这种注解编译时被保留,在class文件中存在,但JVM将会忽略
RUNTIME —— 这种注解将被JVM保留,利用反射机制可以获取并使用。
@Target
@Target注解表明该注解作用的范围。包括package、method、field、构造方法、成员变量、枚举值等属性。
@Inherited
@Inherited注解表明该注解是否影响子类。如果定义的注解上使用了@Inherited标记,则使用该注解的某个父类,它的子类默认继承所有的属性
了解完自定义注解需要使用到的注解,我们开始自定义注解。
SpringBoot工程
POM.xml 中引入以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
自定义注解
package com.zhanglf.aop.annotation;
import java.lang.annotation.*;
/**
* 使用注解统一校验角色权限
* @author zhanglf
* @date 2019-04-29
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionCheck {
//自定义角色值,如果是多个角色,用逗号分割。
public String role() default "";
}
使用Aop进行绑定注解,并在Aop中实现逻辑的权限校验
package com.jd.mee.catalog.aop;
import com.zhanglf.aop.annotation.PermissionCheck;
import com.zhanglf.common.result.CodeMsg;
import com.zhanglf.common.util.JwtUtil;
import com.zhanglf.entity.UserInfo;
import com.zhanglf.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
/**
* 角色权限校验-AOP
* @author hjx
* @date 2020-08-12
*/
@Aspect
@Component
@Slf4j
public class PermissionCheckAspect {
//切入点表达式决定了用注解方式的方法切还是针对某个路径下的所有类和方法进行切,方法必须是返回void类型
@Pointcut("@annotation(com.zhanglf.aop.annotation.PermissionCheck)")
private void permissionCheckCut(){};
//定义了切面的处理逻辑。即方法上加了@PermissionCheck
@Around("permissionCheckCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
log.info("==========进入AOP============================");
//1.记录日志信息
Signature signature = pjp.getSignature();
String className = pjp.getTarget().getClass().getSimpleName();
String methodName = signature.getName();
log.info("className:{},methodName:{}",className,methodName);
//2.角色权限校验
MethodSignature methodSignature = (MethodSignature)signature;
Method targetMethod = methodSignature.getMethod();
if(targetMethod.isAnnotationPresent(PermissionCheck.class)){
//获取方法上注解中表明的权限
PermissionCheck permission = (PermissionCheck)targetMethod.getAnnotation(PermissionCheck.class);
String role = permission.role();
log.info("当前接口请求的用户角色role:{}",role);
if(StringUtils.isNotEmpty(role)){
String[] roles = role.split(",");//接口允许的角色
List<String> list = Arrays.asList(roles);
//如果该接口只允许老师角色访问。则要获取当前用户是不是老师角色。
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String authorization = request.getHeader("Authorization");
UserInfo userInfo = JwtUtil.parseAccessToken(authorization);
String userRole = userInfo.getUserRole();//用户的角色
if(list.contains(userRole)){
log.info("AOP权限角色校验通过,进入业务层处理!");
//3.执行业务逻辑,放行
return pjp.proceed();
}else{
//如果没有权限,抛出异常,由Spring框架捕获,跳转到错误页面
throw new BizException(CodeMsg.ROLE_HAVE_NO_PERMISSION);
}
}
}
throw new BizException(CodeMsg.NO_ROLE_CONFIGER);
}
}
aop的使用:用在接口层校验登陆的角色是否有权限使用该接口
@PermissionCheck
@PostMapping("/delete")
public R delete(@RequestParam String id) {
boolean result = scenarioService.delete(id);
return R.data(result);
}