IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> RBAC0模型的AOP实现 -> 正文阅读

[Java知识库]RBAC0模型的AOP实现

目录

一、简介

二、接口权限控制的实现

1、数据库表

2、后端代码实现

1. 添加AOP依赖

2. 编写自定义注解

3. 编写切面类

4. 使用自定义注解限制用户访问

三、数据权限控制的实现

1、后端代码实现

1. 编写自定义注解

2. 编写切面类

3. 使用自定义注解限制参数


一、简介

RBACRole-based access control)全称为基于角色的访问控制模型,在该模型中,通过让权限与角色关联来实现授权,给用户分配一系列的角色来让注册用户得到这些角色对应的权限,使系统权限分配更加方便。

用户权限控制分下面3类:

访问权限: 哪些页面可以访问、哪些页面元素可见等等

操作权限: 如页面按钮是否可点击、是否可以增删改查等等

接口与数据权限: 接口是否可以调用、接口具体字段范围等等

前面2类可以在前端页面来实现,后面的接口和数据权限可以在后端进行实现。

二、接口权限控制的实现

1、数据库表

我们在数据库中设计5种类型的表。

?如某系统角色权限设计如下:

  • t_auth_role中的code(表示等级)有Lv0、Lv1、Lv2,等级越高,权限和功能越多。
  • ?在数据库中写入用户Tom的权限数据,让Tom在t_user_role中关联角色表中Lv0的等级。
  • 角色后面不同的功能也可以关联不同的等级来实现权限管理。

2、后端代码实现

我们通过Spring AOP的前置通知功能在Controller层检测某用户访问某URL的时候,携带的token来解析出的UserId来查询数据库是否符合等级要求。

1. 添加AOP依赖

        <!--AOP,跟springboot版本一致-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.7.3</version>
        </dependency>

2. 编写自定义注解

?在domain实体类层下创建annotation\ApiLimitedRole注解类

import org.springframework.stereotype.Component;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)    //在运行阶段
@Target({ElementType.METHOD})    //标注放在方法上
@Documented
@Component        //注入
public @interface ApiLimitedRole {

    //    将来用于标志限制URL访问的禁止权限
    String[] limitedRoleCodeList() default {};
}

3. 编写切面类

在Api(也就是Controller)类层下创建aspect\ApiLimitedRoleAspect类。

通过@apiLimitedRole注解传入的禁止访问的等级code,该code跟user拥有的权限等级code取交集,如果交集值大于0,说明该用户的权限等级在被禁止的名单中,则被禁止访问该URL。

@Aspect
@Order(1)
@Component
public class ApiLimitedRoleAspect {

    @Resource
    private UserSupport userSupport;  //用来通过request查询token中含的userId

    @Resource
    private UserRoleService userRoleService;    //用来查询userId拥有的权限code

    // 切点(也就是使用@apiLimitedRole注解的位置)
    @Pointcut("@annotation(com.yygs.bilibili.domain.annotation.ApiLimitedRole)")
    public void check() {
    }

    // AOP前置通知
    // 并通过注解传入禁止访问的等级code
    @Before("check() && @annotation(apiLimitedRole)")    
    public void doBefore(JoinPoint joinPoint, ApiLimitedRole apiLimitedRole) {
        Long userId = userSupport.getCurrentUserId();

        // 查询数据库获得的用户权限
        List<UserRole> userRoleList = userRoleService.getUserRoleByUserId(userId);

        // 通过注解传入权限不足的等级
        String[] limitedRoleCodeList = apiLimitedRole.limitedRoleCodeList();
        Set<String> limitedRoleCodeSet = Arrays.stream(limitedRoleCodeList).collect(Collectors.toSet());

        // 用户有的权限code
        Set<String> roleCodeSet = userRoleList.stream().map(UserRole :: getRoleCode).collect(Collectors.toSet());

        // 取交集
        roleCodeSet.retainAll(limitedRoleCodeSet);
        if (roleCodeSet.size() > 0) {
            throw new ConditionException("权限不足!");
        }
    }
}

4. 使用自定义注解限制用户访问

?注解中的值AuthRoleConstant.Role_LV0是一个常量,对应数据库中的Lv0。因为在开始的时候我们给Tom添加的权限等级为Lv0,那么如果Tom访问/user-moments的URL的时候会抛出“权限不足!”的异常通知。

    @ApiLimitedRole(limitedRoleCodeList = {AuthRoleConstant.ROLE_LV0})
    @PostMapping("/user-moments")
    public JsonResponse<String> addUserMoments(@RequestBody UserMoment userMoment) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        Long userId = userSupport.getCurrentUserId();
        userMoment.setUserId(userId);
        userMomentsService.addUserMoments(userMoment);
        return JsonResponse.success();
    }

这样通过注解和赋值code就可以限制URL的访问等级就变得优雅很多,也比较灵活。那么在后面添加功能和角色之后,如果角色变得十分多,还可以通过添加权限组的方法解决,只要用户在权限组中,或者权限在角色组中就可以访问,以此简化代码。

三、数据权限控制的实现

1、后端代码实现

1. 编写自定义注解

在domain实体类下创建annotation\DataLimited注解类

import org.springframework.stereotype.Component;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
@Component
public @interface DataLimited {

}

2. 编写切面类

?在Api(也就是Controller)层下创建asperct\DataLimitedAspect类。

如果角色的等级是Lv0,且传入的参数不是“0”,则参数异常(也就是限制等级Lv0传某数据的参数只能为0),以此进行数据权限的管理。

@Aspect
@Order(1)
@Component
public class DataLimitedAspect {

    @Resource
    private UserSupport userSupport;

    @Resource
    private UserRoleService userRoleService;

    @Pointcut("@annotation(com.yygs.bilibili.domain.annotation.DataLimited)")
    public void check() {
    }

    @Before("check()")
    public void doBefore(JoinPoint joinPoint) {

        // 通过request获取token携带的userId
        Long userId = userSupport.getCurrentUserId();

        // 查询数据库获得用户的全部权限
        List<UserRole> userRoleList = userRoleService.getUserRoleByUserId(userId);

        // 转换成Set,去重
        Set<String> roleCodeSet = userRoleList.stream().map(UserRole :: getRoleCode).collect(Collectors.toSet());

        // 从参数获得数据
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {

            // 如果有userMoment这个参数
            if (arg instanceof UserMoment) {
                UserMoment userMoment = (UserMoment) arg;
                String type = userMoment.getType();

                // 如果角色是Lv0,且传入的参数不是“0”,则参数异常(也就是Lv0只能传参数0)
                if (roleCodeSet.contains(AuthRoleConstant.ROLE_LV0) && !"0".equals(type)) {
                    throw new ConditionException("参数异常");
                }
            }
        }
    }
}

3. 使用自定义注解限制参数

    @ApiLimitedRole(limitedRoleCodeList = {AuthRoleConstant.ROLE_LV0})
    @DataLimited    //限制数据(参数的传入)
    @PostMapping("/user-moments")
    public JsonResponse<String> addUserMoments(@RequestBody UserMoment userMoment) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        Long userId = userSupport.getCurrentUserId();
        userMoment.setUserId(userId);
        userMomentsService.addUserMoments(userMoment);
        return JsonResponse.success();
    }

除了通过注解进行权限的控制还可已通过过滤器、拦截器进行URl的拦截。但是通过AOP的注解标注方法对用户进行权限控制,是比较优雅的,AOP的粒度更小,也是比较灵活的。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-25 23:07:17  更:2022-09-25 23:08:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:30:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码