引言

在我们做项目的时候可能会遇到这样的场景:给用户分配不同的角色,然后不同的角色对某一个方法有不同的权限,有些角色可以访问该方法,有的不能访问。这时候我们可以利用aop实现权限验证。

实现思路就是首先自定义一个注解,在方法上添加该注解,跟据注解的值来判断能否访问该方法。

创建SpringBoot项目

导入依赖

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <commons.io.version>2.5</commons.io.version>
        <commons.fileupload.version>1.3.3</commons.fileupload.version>
        <poi.version>4.1.2</poi.version>
    </properties>


    <dependencies>
        <!--aop-->
        <!--AOP联盟-->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!--Spring Aspects-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--aspectj-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- excel工具 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <!--io常用工具类 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons.io.version}</version>
        </dependency>
        <!--文件上传工具类 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>${commons.fileupload.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 日志 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
            <exclusions>            <!-- 排除spring-boot-starter-logging中的全部依赖 -->
                <exclusion>
                    <groupId>*</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
            <scope>test</scope>     <!-- 打包的时候不打spring-boot-starter-logging.jar -->
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
    </dependencies>

配置application.yml

mybatis:
  mapper-locations: classpath:/mybatis/**/*.xml
  type-aliases-package: com.example.note.domain
  map-underscore-to-camel-case: true
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  typeAliasesPackage: com.example.note.domain  #存放实体类的目录路径
  mapperLocations: classpath:mybatis/**/*.xml
  # 全局配置id自增  =>
  global-config:
    db-config:
      id-type: auto

server:
  port: 8088
spring:
  application:
    name: note-back
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    name: defaultDataSource
    password: '123456789'
    url: jdbc:mysql://localhost:3306/note?serverTimezone=UTC
    username: 'root'

数据准备

自定义注解

package com.example.noteback.permission.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//目标是方法(在方法上添加该注解)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permissions {
    public String value();
}

创建controller类,定义两个方法

package com.example.noteback.permission.controller;

import com.example.noteback.permission.anno.Permissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("permissions")
public class PermissionsController {

    @Permissions(value = "/permissions/getUser")
    @GetMapping("/getUser")
    public String getUser(){
        return "User";
    }

    @Permissions(value = "/permissions/getAGi")
    @GetMapping("/getAGi")
    public String getAGi(){
        return "AGi";
    }
}

AOP实现权限验证

创建PermissionsValidation类(类名自定义)

import com.example.noteback.permission.anno.Permissions;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

@Aspect
@Component
public class PermissionsValidation {
    //切入点
    @Pointcut("@annotation(com.example.noteback.permission.anno.Permissions)")
    public void permissionsPoint() {
    }

    @Around("permissionsPoint()")
    public Object hasPermissions(ProceedingJoinPoint joinPoint) throws Throwable {
    }


}

定义切入点,放到上面的PermissionsValidation类里面

    //切入点
    /*当我们调用添加 @Permissions 注解的方法时,
    下面的方法自动获取被调用的方法*/
    @Pointcut("@annotation(com.example.noteback.permission.anno.Permissions)")
    public void permissionsPoint() {

    }

使用环绕通知@Around实现权限验证,放到上面的PermissionsValidation类里面

    //通过方法名获取切入点
    @Around("permissionsPoint()")
    public Object hasPermissions(ProceedingJoinPoint joinPoint) throws Throwable {
        //方法签名
        MethodSignature methodSignature=(MethodSignature) joinPoint.getSignature();
        //获取方法
        Method aimMethod= methodSignature.getMethod();
        //获取 @Permissions 的值
        String permissions=aimMethod.getAnnotation(Permissions.class).value();
        //权限集合
        List<String> permissionsList=new ArrayList<>();
        permissionsList.add("/permissions/getUser");
        //返回数据
        Object proceed=null;
        //如果权限集合包含 @Permissions 的值
        if(permissionsList.contains(permissions)){
            //允许通过,表调用的方法可以往下运行
            proceed=joinPoint.proceed();
        }else {
            proceed="没有权限";
        }
        return proceed;
    }

编写完毕

测试 

上面定义的权限集合只包含 "/permissions/getUser"

访问:http://127.0.0.1:8088/permissions/getUser

  访问:http://127.0.0.1:8088/permissions/getAGi

源码地址 

源码地址:git@gitee.com:AGi_R/note.git

在命令框输入:git clone git@gitee.com:AGi_R/note.git 直接下载源码

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐