java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot AOP统一角色权限校验

SpringBoot使用AOP实现统一角色权限校验

作者:天罡gg

这篇文章主要介绍了SpringBoot如何使用AOP实现 统一角色权限校验,文中有详细的代码示例讲解和操作流程,具有一定的参考价值,需要的朋友可以参考下

一、引入AOP starter

在tg-book-common中引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

对于spring boot的starter,我在之前的文章中已经反复说明过多次,不做赘述!
本项目中已经使用中的starter如下:

二、创建切面@Aspect + 定义切点@Pointcut

@Aspect注解方式,它的概念像@Aspect、@Pointcut、@Before、@After、@Around等注解都是来自于 AspectJ,但是功能的实现是纯 Spring AOP 自己实现的,主要有两大核心

以下使用@Aspect 定义一个切面类,使用@Pointcut定义一个切点,切点表达式使用@annotation方式,也就是注解的方式。

// @Aspect和@Component定义一个切面类,@Slf4j是之前讲过的日志注解
@Component
@Aspect
@Slf4j
public class RoleAspect {
	// 核心一:定义切点(使用@annotation方式)
    @Pointcut(value = "@annotation( org.tg.book.common.annotation.Role)")
    public void pointCut() {}
}

三、封装校验@Role角色权限的方法

本文的AOP是上文拦截器Interceptor的另一种实现方式,所以请将上文的AuthInterceptor中的如下代码注释:

然后把这段代码拿过来,封装成一个方法,放到RoleAspect 中如下:

/**
 * 将@Role与登录用户的角色对比,如果是管理员返回true
 **/
private boolean checkAdminRole(Role role)  {
    // 校验角色
    if (role != null) {
        // 走到这,说明方法上加了@Role
        boolean isAdmin = false;
        AuthContextInfo authInfo = AuthContextInfo.getAuthInfo();
        for (int roleId : role.roleIds()) {
            if (authInfo.getRoleId().equals(roleId)) {
                isAdmin = true;
                break;
            }
        }
        if (!isAdmin) {
            log.info("[403]无权限, authInfo={}", authInfo);
            return false;
        }
    }
    return true;
}

方法逻辑很简单:将@Role与登录用户的角色对比,如果是管理员返回true,否则返回false

四、AOP两种实现方式

4.1 前置通知@Before方式

因为角色权限校验代码,发生于【业务方法代码】之前,所以可以使用前置通知@Before方式,代码如下:

@Before("pointCut()")
public void before(JoinPoint joinPoint) throws NoSuchMethodException {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Class<?> clazz = joinPoint.getTarget().getClass();
    Method method = clazz.getMethod(signature.getName(), signature.getParameterTypes());
    Role role = method.getAnnotation(Role.class);
    boolean isAdminRole = checkAdminRole(role);
    if (!isAdminRole) {
        throw new RuntimeException("无权限");
    }
}

核心逻辑是获得@Role注解,然后进行校验,如果非管理员,则抛出异常。这里实现的比较简单,当后面我们实现了【全局异常处理】以后,这里就可以换成自定义的异常类,交给【全局异常处理】统一处理!

4.2 环绕通知@Around方式

如果不抛出异常的话,如何处理?

可以使用@Around方式,环绕通知@Around可以控制在【业务方法代码】之前校验,并且可以返回结果,所以我们就不需要抛出异常了!

@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Class<?> clazz = joinPoint.getTarget().getClass();
    Method method = clazz.getMethod(signature.getName(), signature.getParameterTypes());
    Role role = method.getAnnotation(Role.class);
    boolean isAdminRole = checkAdminRole(role);
    if (!isAdminRole) {
        return TgResult.fail("403", "无权限");
    }
    return joinPoint.proceed();
}

获取Role 之前的代码都是一模一样的,区别就是这里没有抛出异常,而是返回统一结果TgResult,这也正是封装统一返回结果的好处之一!!!

特别注意: before和around是两种实现方式,所以不必在意从joinPoint得到role的重复代码,因为最终只会写一份代码,对于before和around我更建议使用around的方式!

以上就是SpringBoot使用AOP实现统一角色权限校验的详细内容,更多关于SpringBoot AOP统一角色权限校验的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文