若依管理系统RuoYi-Vue:权限系统设计详解

news2024/11/26 14:51:49

文章目录

  • 摘要
  • 数据库表结构设计
  • 菜单管理
    • 目录、菜单和按钮的区别
    • 菜单权限
  • api接口权限
    • 配置方法
    • @PreAuthorize注解介绍
    • 数据权限
  • 前端vue权限拦截
    • 菜单权限
    • 按钮权限

摘要

若依(RuoYi)是一款基于Spring Boot和Vue.js开发的快速开发平台,它的权限管理是通过RBAC(Role-based Access Control 基于角色的访问控制)模型来设计的。

RBAC模型将权限控制分为角色管理和权限管理两个部分。在若依中,角色是指对系统的一类用户或操作者的定义,而权限是指对系统中某个资源或操作的访问控制。通过为每个角色分配相应的权限,可以实现对系统的全面管理和控制。

具体来说,在若依中,权限管理包括以下几个方面:

  1. 菜单管理:通过对系统菜单进行管理,可以控制用户在系统中能够访问的页面和功能。

  2. 按钮权限:在系统中,某些操作需要特定的权限才能进行,例如删除、修改等操作。通过对按钮权限的控制,可以限制用户对系统的访问和操作。

  3. 数据权限:在某些情况下,需要根据用户的角色或部门来限制其对数据的访问。通过数据权限的设置,可以实现对数据的细粒度控制。

  4. API接口权限:在若依中,API也可以通过权限的方式进行控制。通过对API的权限进行管理,可以限制用户对API的访问和使用。

数据库表结构设计

在数据库表结构方面,若依采用了RBAC模型的设计。其中,主要包括以下表:

  • sys_menu:存储系统菜单信息,包括菜单ID、菜单名称、访问路径、菜单类型等字段。
  • sys_role:存储系统角色信息,包括角色ID、角色名称、角色标识、角色描述等字段。
  • sys_user:存储系统用户信息,包括用户ID、用户名、密码、昵称、邮箱、电话等字段。
  • sys_role_menu:存储角色和菜单之间的关联关系,包括角色ID和菜单ID两个字段。
  • sys_user_role:存储用户和角色之间的关联关系,包括用户ID和角色ID两个字段。

通过这些表的设计,可以实现对系统中菜单、角色和用户的管理。同时,通过角色和菜单之间的关联关系,可以实现对菜单访问权限的控制。通过用户和角色之间的关联关系,可以实现对用户访问权限的控制。

菜单管理

目录、菜单和按钮的区别

在若依(RuoYi)中,菜单和目录是两个不同的概念,它们之间的区别如下:

  1. 目录(Directory):

目录是用来组织和分类菜单的容器。目录本身没有功能,它只是一个容器,可以包含若干个菜单。目录通常是一个抽象的概念,用于将一组相关的菜单组织在一起。

在若依中,目录是以“系统管理”、“运营管理”等大模块的方式组织菜单的,用于区分不同的功能模块。目录通常以左侧的菜单树的形式展现,用户可以通过点击不同的目录来展开或收缩对应的菜单列表。

  1. 菜单(Menu):

菜单是具有一定功能的操作项,通常是一组具有相同功能的页面或功能点的集合。每个菜单通常对应一个页面或者一个功能模块。

在若依中,菜单通常是以左侧的树形菜单的形式展现,用户可以通过点击不同的菜单来跳转到对应的页面或功能模块。每个菜单都有一个唯一的标识符,通常以URL的形式表示。

  1. 按钮(Button):

按钮是指菜单中的操作按钮,用于触发一些具体的操作。在若依中,按钮通常是与表格或表单等组件配合使用的,用于进行数据的增删改查等操作。按钮通常会与权限控制结合起来,只有拥有相应权限的用户才能看到并使用该按钮。

总的来说,目录、菜单、按钮是若依系统中的三种不同的概念。目录是为了方便管理菜单和模块,菜单是系统的核心功能模块,按钮是菜单中的具体操作按钮。在实际应用中,它们通常会结合起来,形成一个完整的用户界面和操作流程。
在这里插入图片描述
在这里插入图片描述

菜单权限

在若依中,实现不同用户看到不同的菜单可以通过以下步骤实现:

  1. 在数据库中维护菜单的权限信息,可以为每个菜单设置一个权限标识。

  2. 在用户登录系统时,将该用户所拥有的菜单权限信息从数据库中获取出来。

  3. 根据用户的菜单权限信息动态生成菜单,使用户只能看到其拥有权限的菜单。

用户登录之后会请求后端的com.ruoyi.web.controller.system.SysLoginController#getRouters接口获取登录用户的菜单数据:

select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
		from sys_menu m
			 left join sys_role_menu rm on m.menu_id = rm.menu_id
			 left join sys_user_role ur on rm.role_id = ur.role_id
			 left join sys_role ro on ur.role_id = ro.role_id
			 left join sys_user u on ur.user_id = u.user_id
		where u.user_id = #{userId} and m.menu_type in ('M', 'C') and m.status = 0  AND ro.status = 0
		order by m.parent_id, m.order_num

菜单类型(M目录 C菜单 F按钮);菜单状态(0显示 1隐藏)

前端会根据该接口返回的数据渲染出不同的菜单。

api接口权限

配置方法

每一个按钮基本上都会对应着一个后端的接口,前端会根据权限标志显示或者隐藏按钮,但是如果用户不点击按钮,直接通过http请求工具请求后端咋办?所以接口权限也是要有的,该权限和按钮上权限完全一致。

若依系统使用了SpringSecurity框架,接口权限都是基于注解@PreAuthorize实现的,比如,用户管理页面中的修改用户按钮对应的后端接口长这个样子。

    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysUser user)
    {
        ...
    }

和其对应的前端按钮权限标志一样
在这里插入图片描述
如果没有权限访问接口,则会返回类似如下信息:

{
"msg": "请求访问:/system/user/list,认证失败,无法访问系统资源",
"code": 401
}

@PreAuthorize注解介绍

目前若依的注解使用的是Spring Security提供的@PreAuthorize注解,并通过EL表达式的方式调用SecurityUtils中的hasPermission方法来实现对权限的控制。

@PreAuthorize注解可以在方法执行前进行权限校验,如果校验不通过则会抛出AccessDeniedException异常,表示拒绝访问。该注解的参数可以是一个字符串表达式,也可以是一个SpringEL表达式。在若依中,@PreAuthorize注解中的SpringEL表达式@ss.hasPermi(‘system:user:edit’)表示调用SecurityUtils中的hasPermission方法,并传入参数system:user:edit,判断当前用户是否有该权限。

hasPermission方法的实现在SecurityUtils类中,它会获取当前用户的角色和权限信息,并判断当前用户是否拥有指定的权限。如果有该权限则返回true,否则返回false。

public boolean hasPermission(String permission) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication == null) {
        return false;
    }
    Object principal = authentication.getPrincipal();
    if (principal instanceof UserDetails) {
        UserDetails userDetails = (UserDetails) principal;
        return userDetails.getAuthorities().contains(new SimpleGrantedAuthority(permission));
    }
    return false;
}

数据权限

数据权限实现的关键在于com.ruoyi.framework.aspectj.DataScopeAspect类。该类是一个切面类,凡是加上com.ruoyi.common.annotation.DataScope注解的方法,在执行的时候都会被它拦截。

该切面定义了五种权限范围
在这里插入图片描述
该切面的核心逻辑是“拼SQL”,方法执行之前,会给参数的一个params属性添加一个dataScope键值对,key为"dataScope",值为AND (" + sqlString.substring(4) + ")"样式的一段SQL,这段SQL会根据当前用户所在的部门以及当前用户角色的权限范围发生变化。

StringBuilder sqlString = new StringBuilder();
        for (SysRole role : user.getRoles())
        {
            String dataScope = role.getDataScope();
            if (DATA_SCOPE_ALL.equals(dataScope))
            {
                sqlString = new StringBuilder();
                break;
            }
            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
            {
                sqlString.append(StringUtils.format(
                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
                        role.getRoleId()));
            }
            else if (DATA_SCOPE_DEPT.equals(dataScope))
            {
                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
            }
            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
            {
                sqlString.append(StringUtils.format(
                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                        deptAlias, user.getDeptId(), user.getDeptId()));
            }
            else if (DATA_SCOPE_SELF.equals(dataScope))
            {
                if (StringUtils.isNotBlank(userAlias))
                {
                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
                }
                else
                {
                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
                    sqlString.append(" OR 1=0 ");
                }
            }
        }

以用户列表查询为例,执行sql为

    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
		left join sys_dept d on u.dept_id = d.dept_id
		where u.del_flag = '0'
		<if test="userName != null and userName != ''">
			AND u.user_name like concat('%', #{userName}, '%')
		</if>
		<if test="status != null and status != ''">
			AND u.status = #{status}
		</if>
		<if test="phonenumber != null and phonenumber != ''">
			AND u.phonenumber like concat('%', #{phonenumber}, '%')
		</if>
		<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
			AND date_format(u.create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
		</if>
		<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
			AND date_format(u.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
		</if>
		<if test="deptId != null and deptId != 0">
			AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
		</if>
		<!-- 数据范围过滤 -->
		${params.dataScope}
	</select>

前端vue权限拦截

菜单权限

菜单权限很简单,实际上就是简单的用户-角色-菜单模型,那么菜单是什么时候加载的呢?ruoyi-ui\src\permission.js,加载的逻辑在这个文件中。

permission.js文件中设置了导航守卫,每次路由发生变化的时候就会触发router.beforeEach的回调函数。

router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    /* has token*/
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      if (store.getters.roles.length === 0) {
        // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(res => {
          // 拉取user_info
          const roles = res.roles
          store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        }).catch(err => {
            store.dispatch('LogOut').then(() => {
              Message.error(err)
              next({ path: '/' })
            })
          })
      } else {
        next()
      }
    }
  } else {
    // 没有token
    if (whiteList.indexOf(to.path) !== -1) {
      // 在免登录白名单,直接进入
      next()
    } else {
      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      NProgress.done()
    }
  }
})

按钮权限

看下系统管理下的菜单管理中的修改、新增和删除按钮前端vue代码

<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button size="mini" 
            type="text" 
            icon="el-icon-edit" 
            @click="handleUpdate(scope.row)"
            v-hasPermi="['system:menu:edit']"
          >修改</el-button>
          <el-button 
            size="mini" 
            type="text" 
            icon="el-icon-plus" 
            @click="handleAdd(scope.row)"
            v-hasPermi="['system:menu:add']"
          >新增</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['system:menu:remove']"
          >删除</el-button>
        </template>
      </el-table-column>

el-button上有个属性v-hasPermi,这实际上是vue的自定义指令,属性值就是创建按钮的时候定义的那个权限标志。其定义在src/directive/permission/index.js文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/513526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

今天面了个阿里拿25k出来的小哥,让我见识到了什么是测试天花板

2022年堪称大学生就业最难的一年&#xff0c;应届毕业生人数是1076万。失业率超50%&#xff01; 但是我观察到一个数据&#xff0c;那就是已经就业的毕业生中&#xff0c;计算机通信等行业最受毕业生欢迎&#xff01; 计算机IT行业薪资高&#xff0c;平均薪资是文科其他岗位的…

优秀CRM系统的四个条件

如今&#xff0c;构建“以客户为中心”的经营模式&#xff0c;是许多企业提升竞争力的核心战略。CRM系统能够管理客户关系&#xff0c;提高销售线索转化率&#xff0c;帮助企业实现业绩增长。那么众多品牌中&#xff0c;CRM系统哪家公司做得更好&#xff1f; CRM做得好有哪几个…

Vue换肤主题

拷贝颜色选择组件 **ThemePicker <template><!-- navabar的换肤组件 --><el-color-pickerv-model="theme":predefine="[#409EFF,

智慧校园水电节能监管系统

现阶段各高校用电设备量多范围广&#xff0c;包含寝室、办公室、教室、会议厅、试验室、公共图书馆、运动场馆、饭堂、路面、园林绿化等地方&#xff0c;能耗极大。而且大多数节能意识薄弱&#xff0c;欠缺科学合理、科学合理的规章制度开展监管&#xff0c;造成电力能源很多消…

达索的全面的三维设计和产品开发工具CATIA V5-6R 2020版本下载与安装配置教程

目录 前言一、CATIA 安装二、CATIA更新包安装三、使用配置四、帮助文档安装&#xff08;非必要&#xff09;总结 前言 Dassault Systemes公司的CATIA软件是一种基于计算机辅助设计&#xff08;CAD&#xff09;和计算机辅助制造&#xff08;CAM&#xff09;的软件&#xff0c;用…

Vue(组件间通信:props、自定义事件、全局事件总线、消息订阅与发布)

一、props props不仅可以实现父给子传递信息&#xff0c;还可以进行子给父传递信息 1.父给子传递信息&#xff1a; 父组件中给子组件实例传递信息 子组件利用props进行接收组件传递信息&#xff08;接收方式有三种&#xff1a;数组、对象、配置对象&#xff09; 2.子给父传递…

【表面缺陷检测】基于yolov5的布匹表面缺陷检测(附代码和数据集)

写在前面: 首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 路虽远,行则将至;事虽难,做则必成。只要有愚公移山的志气、滴水穿石的毅力,脚踏实地,埋头苦干,积跬步以至千里,就…

Mybatis Plus 入门 简单的CRUD 使用详解 条件查询 分页查询 DML操作 MP代码生成器

Mybatis Plus入门 MP是 MybatisPlus&#xff0c;简称MP&#xff0c;是一个 Mybatis 的增强工具&#xff0c;在 Mybatis 的基础上只做增强不做改变。MP为简化开发、提高效率而生。 它已经封装好了单表curd方法&#xff0c;我们直接调用这些方法就能实现单表CURD。 注意&#xf…

一分钟图情论文:《AIGC驱动的智慧图书馆转型:框架、路径与挑战》

一分钟图情论文&#xff1a;《AIGC驱动的智慧图书馆转型&#xff1a;框架、路径与挑战》 AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;是一种全新的生产方式&#xff0c;利用人工智能技术自动生成文本、图片、语音、视频甚至虚拟现实等各种形式的数…

5 创建映射

5 映射 上边章节安装了ik分词器&#xff0c;如果在索引和搜索时去使用ik分词器呢&#xff1f;如何指定其它类型的field&#xff0c;比如日期类型、数 值类型等。 本章节学习各种映射类型及映射维护方法。 5.1 映射维护方法 1、查询所有索引的映射&#xff1a; GET&#xf…

【MCAL_UART】-1.2-图文详解RS232,RS485和MODBUS的关系

目录 1 UART&#xff0c;RS232和RS485通信拓扑 2 什么是RS232 2.1 RS232标准的演变 2.2 RS232标准讲了哪些 2.2.1 RS232通信的电平 2.2.2 RS232通信的带宽 2.2.3 RS232通信距离 2.2.4 RS232通信的机械接口 3 什么是RS485 3.1 RS485标准的演变 3.2 RS485标准讲了哪些…

java运算符和表达式

文章目录 一、Java运算符和表达式二、Java算数运算符实例讲解三、Java关系运算符实例讲解四、Java逻辑运算符实例讲解五、Java位运算符实例讲解六、Java赋值运算符实例讲解七、Java条件运算符实例讲解八、Java instanceof运算符实例讲解九、Java运算符的优先级和结合性总结 一、…

steam/CSGO搬砖绝对是副业中的天花板

这个项目的主要逻辑就是——把Steam上CSGO的装备卖到国内上的平台&#xff0c;网易buff去交易赚一个汇率差。 这玩法有点像新疆出产的棉花占全国产量的85%&#xff0c;当地产量大&#xff0c;价格相对其他不产棉花的地区来说&#xff0c;自然就便宜了&#xff1b; 那么就会有商…

gazebo仿真

常用的仿真器 nvidia 场景非常真实&#xff0c;收费 物理仿真比较好&#xff0c;渲染差一点 为什么用仿真器&#xff0c;因为比较穷 gazebo与ros集成的比较好&#xff0c;有很多插件&#xff0c;机器人开发 刚体仿真器 ode 安装gazebo ros自带 机器人算法开发与验证 打开…

2023年湖北武汉安全员ABC报名条件和报名资料是什么?全国通用?

2023年湖北武汉安全员ABC报名条件和报名资料是什么&#xff1f;全国通用&#xff1f; 一、湖北安全员ABC报名条件要求&#xff1a; 1.安全员A证针对的是企业主要负责人&#xff0c;包括法定代表人、总经理&#xff08;总裁&#xff09;、分管安全生产的副总经理&#xff08;副…

java版本spring cloud 企业电子招投标采购系统源码之首页设计

​ ​功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 全程数字化的采购管理 智能化平台化电子化内外协同 明理满足采购业务全程数字化&#xff0c; 实现供应商管理、采购需求、全网寻源、全网比价、电子招 投标、合同订单执行的…

医疗血氧仪方案产品规格书

血氧仪是一种测量人体血氧饱和度的医疗设备&#xff0c;它通过指夹感应器将光源通过皮肤照射到血液中&#xff0c;测量出血液的血氧饱和度&#xff0c;从而帮助医生判断患者是否有缺氧的情况。下面是一份血氧仪产品规格书&#xff0c;具体内容如下&#xff1a; 产品名称&#x…

select、poll、epoll之间的区别总结[整理]

select&#xff0c;poll&#xff0c;epoll都是IO多路复用的机制。I/O多路复用就通过一种机制&#xff0c;可以监视多个描述符&#xff0c;一旦某个描述符就绪&#xff08;一般是读就绪或者写就绪&#xff09;&#xff0c;能够通知程序进行相应的读写操作。但select&#xff0c;…

gitlab cicd

CICD是指持续集成和部署&#xff0c;一般涵盖以下过程 常规步骤如下&#xff1a; 1、代码开发 2、代码提交(dev分支) 3、 持续集成自动检查和编译 包含&#xff1a;1、sonar初步检查&#xff0c;代码规范 2、自动编译&#xff0c;代码正确性检查 3、单元测试&#xff0c;goo…

2023年,网络安全方面 5 大值得学习的编程语言

Python 到目前为止&#xff0c;Python 在网络安全领域一直处于领先地位。这是一种通用的服务器端脚本语言&#xff08;无需编译&#xff09;&#xff0c;已经被应用到成千上万的安全项目中。你会发现绝大多数安全工具和 PoCs 都是用 Python 编写的&#xff0c;这样做是有充分理…