若依笔记(三):权限控制与数据隔离

目录

数据隔离/权限控制

用户/权限/部门/岗位

​数据隔离

mybatis的maaper写法

注解和切面

前端路由拦截


已知若依单体的前端采用vue-element-admin,在前端的专栏系列vue-element-admin的动态路由已详细拆解,其最大特点是使用后端返回数据控制前端菜单,每次接口请求前会有路由拦截来获取权限和菜单列表并重新渲染页面,配合若依后端自己实现的数据权限切面,能够实现很好地的数据隔离和权限隔离,那么现在就从代码层面分析其实现;

数据隔离/权限控制

若依系统的权限控制实体分为目录-->菜单-->按钮,最小到按钮级别,也就是针对某个表可以控制其是否能够删除或新增,普通用户只能查看筛选(查);

  • 目录:左侧菜单栏
  • 菜单:耳机菜单
  • 按钮:数据的增删改查操作

用户/权限/部门/岗位

权限控制主体是用户,用户具有角色、部门、岗位的细分属性,

  • 角色:角色可以控制菜单,角色意味着该用户具备哪些数据的管理操作权限,可以在角色编辑栏针对角色来控制不同的菜单项;
  • 部门:部门不涉及权限,但涉及组织架构,当树形展开部门组织架构后,可以清晰明了地知道用户隶属于什么部门,及其岗位是啥,只是用户的某个属性;
  • 岗位:岗位也只是用户的某个属性,岗位与角色关联,比如测试组的负责人应该可以查看所有测试表的数据,那么可以给这个负责人用户1个test-admin角色,给其测试表的所有操作权限,同理,研发和营销人员都应该有1个对应的admin角色,通过角色控制对应部门的菜单列表;

刚才说可以通过定义角色权限来控制目录+菜单,实现不同的部门看不同的菜单栏,那么如果同一个部门内部,比如营销人员A和营销人员B,A是小组长可以新增任务,B只能查看和认领/修改,那么这就涉及同一个表的按钮级别权限,可以新建一个营销的comon角色,该角色只能查看按钮;

 数据隔离

上面从功能层面描述了权限管理体系,也就是实现从前端去控制用户的操作权限,那么后端的数据如何做到数据隔离呢?数据隔离就是不同部门看隶属于其部门的数据,部门A和部门B的common普通用户都有查看<施工监测>这个目录--->菜单的权限,并且均有查看权限,那么其查看的数据应该是跟部门绑定的,这就是通过后端切面来实现的;

mybatis的maaper写法

我们来看代码生成器生成的mapper怎么写的,sql的where循环条件最后一行有params.dataScope的这个字符串,它是入参ProjectJklc这个pojo类的某个属性,这里可以把他当作1个占位符;

    <select id="selectProjectJklcList" parameterType="ProjectJklc" resultMap="ProjectJklcResult"><include refid="selectProjectJklcVo"/><where>  <if test="gdxc != null "> and gdxc = #{gdxc}</if><if test="zbsl != null "> and zbsl = #{zbsl}</if><if test="gjxc != null "> and gjxc = #{gjxc}</if><if test="scyl != null "> and scyl = #{scyl}</if><if test="cjyl != null "> and cjyl = #{cjyl}</if><if test="gjnl != null "> and gjnl = #{gjnl}</if><if test="tnl != null "> and tnl = #{tnl}</if><if test="mgzl != null "> and mgzl = #{mgzl}</if><if test="wynbwy != null "> and wynbwy = #{wynbwy}</if><if test="xgjy != null  and xgjy != ''"> and xgjy = #{xgjy}</if>${params.dataScope}</where></select>

在 ProjectJklc这个实体定义中继承了BaseEntity,它有params属性,是个map默认是空;

public class ProjectJklc extends BaseEntity
private Map<String, Object> params;

 params在何时被填充的,这个sql何时被补充完整的?可以查看使用这个mapper的impl调用入口,有个注解@DataScope(deptAlias = "project_jklc"),这个注解中定义了deptAlias这个key,翻译过来是部门表别名,意味着这个value是个跨部门访问的表;

    /*** 查询监控量测列表* * @param projectJklc 监控量测* @return 监控量测*/@Override@DataScope(deptAlias = "project_jklc")public List<ProjectJklc> selectProjectJklcList(ProjectJklc projectJklc){return projectJklcMapper.selectProjectJklcList(projectJklc);}
注解和切面

@DataScope注解定义有3个属性,部门表别名,用户表别名,权限字符,实现跨部门跨用户的数据隔离过滤条件;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope
{/*** 部门表的别名*/public String deptAlias() default "";/*** 用户表的别名*/public String userAlias() default "";/*** 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来*/public String permission() default "";
}

在DataScopeAspect切面中有一系列判断,其核心是首先看当前用户所属权限是否限制了本人操作过的数据只有本人能看,或部门内都可以使用,比如当前用户所属角色(营销人员B的营销common角色)若是仅仅本人数据权限就只能查user_id等于她自己的;

判断中角色如果是全部数据权限/all权限不拼接sql,正常情况是本部门可以访问,也就是只做部门间的数据隔离,那么就只拼接dept_id的SQL语句,如下:

            if (DATA_SCOPE_ALL.equals(dataScope)){sqlString = new StringBuilder();conditions.add(dataScope);break;}else if (DATA_SCOPE_DEPT.equals(dataScope)){sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));}

该切面在方法调用前填充了实体中的params属性,在mybaits的mapper使用时候这个实体已经有值了,这样就实现了部门/用户层面的数据隔离。

前端路由拦截

那么代码生成器生成的前端代码如何配合后端来完成按钮级别的控制的呢?这个就涉及到前端代码入侵,在前端<el-button>按钮组件上有个v-hasPermi属性

      <el-col :span="1.5"><el-buttontype="danger"plainicon="el-icon-delete"size="mini":disabled="multiple"@click="handleDelete"v-hasPermi="['system:jklc:remove']">删除</el-button></el-col>

v-hasPermi是自定义指令,用于处理操作权限。它通过获取store中的permissions来判断用户是否有操作权限,如果没有则移除该元素,[system:jklc:query]将被解析成system,jklc,query然后比对permission获取的后端权限list,如果没有比对上,就是fasle,就不会选自然这个el-button组件。

import store from '@/store'export default {inserted(el, binding, vnode) {const { value } = bindingconst all_permission = "*:*:*";const permissions = store.getters && store.getters.permissionsif (value && value instanceof Array && value.length > 0) {const permissionFlag = valueconst hasPermissions = permissions.some(permission => {return all_permission === permission || permissionFlag.includes(permission)})if (!hasPermissions) {el.parentNode && el.parentNode.removeChild(el)}} else {throw new Error(`请设置操作权限标签值`)}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react和vue的区别

目录 react和vue区别的主要区别 react和vue区别的部分详情 1. 语法&#xff1a; 2. 组件化开发&#xff1a; 3. 状态管理&#xff1a; 4. 生态系统&#xff1a; 5. 性能特点&#xff1a; react和vue区别的主要区别 React和Vue是两种流行的JavaScript库&#xff0c;用于构…

pom.xml详解

我们在开发Java应用程序时&#xff0c;pom.xml文件是项目中的核心配置文件之一&#xff0c;它结合Maven实现对项目依赖的拉取&#xff0c;今天就详细了解一下pom.xml文件的配置 Maven是一种构建工具&#xff0c;它用于构建、管理和发布Java项目pom.xml文件包含了项目的所有重要…

降低边际成本:跨境电商的利润增长策略

在竞争激烈的跨境电商领域&#xff0c;降低成本是提高利润的关键。边际成本&#xff0c;即生产或销售一件额外商品所需的额外成本&#xff0c;在跨境电商中起到至关重要的作用。在本文中&#xff0c;我们将探讨降低边际成本的策略&#xff0c;以实现跨境电商的利润增长。 供应链…

苹果M3 Max芯片跑分曝光:GPU性能不及M2 Ultra

驱动中国2023年11月2日消息&#xff0c;近日&#xff0c;据外媒报道&#xff0c;在苹果 M3 芯片现身 GeekBench 跑分库之后&#xff0c;M3 Max 芯片也出现在该跑分平台上。 据悉&#xff0c;搭载 M3 Max 芯片的设备标识符为 Mac15,9&#xff0c;目前共有 4 条信息&#xff0c;其…

【Linux】Nignx的入门使用负载均衡动静分离(前后端项目部署)---超详细

一&#xff0c;Nignx入门 1.1 Nignx是什么 Nginx是一个高性能的开源Web服务器和反向代理服务器。它使用事件驱动的异步框架&#xff0c;可同时处理大量请求&#xff0c;支持负载均衡、反向代理、HTTP缓存等常见Web服务场景。Nginx可以作为一个前端的Web服务器&#xff0c;也可…

微信小程序:实现多个按钮提交表单

效果 核心步骤 通过data-type给不同按钮进行设置&#xff0c;便于很好的区分不同按钮执行不同功能 data-type"" 完整代码 wxml <form action"" bindsubmit"formSubmit"><button style"margin-bottom:5%" data-type"pa…

IDEA创建Springboot多模块项目

一、创建父模块 File --> New --> Project &#xff0c;选择 “ Spring Initalizr ” &#xff0c;点击 Next Next Next --> Finish 二、创建子模块 右键根目录&#xff0c;New --> Module 选择 “ Spring Initializr ”&#xff0c;点击Next 此处注意T…

Springboot JSP项目如何以war、jar方式运行

文章目录 一&#xff0c;序二&#xff0c;样例代码1&#xff0c;代码结构2&#xff0c;完整代码备份 三&#xff0c;准备工作1. pom.xml 引入组件2. application.yml 指定jsp配置 四&#xff0c;war方式运行1. 修改pom.xml文件2. mvn执行打包 五&#xff0c;jar方式运行1. 修改…

R语言绘图-5-条形图(修改坐标轴以及图例等)

0. 说明&#xff1a; 1. 绘制条形图&#xff1b; 2. 添加文本并调整位置&#xff1b; 3. 调整x轴刻度的字体、角度及颜色&#xff1b; 4. 在导出pdf时&#xff0c;如果没有字体&#xff0c;该怎么解决问题&#xff1b; 1. 结果&#xff1a; 2. 代码&#xff1a; library(ggp…

UE5数字孪生制作(一) - QGIS 学习笔记

1.下载 QGIS是免费的GIS工具&#xff0c;下载地址&#xff1a; https://www.qgis.org/en/site/ 2.安装 - 转中文 按照步骤安装&#xff0c;完成后&#xff0c;在菜单 设置settings里&#xff0c;选择options&#xff0c;修改语言 确定后&#xff0c;需要重启下软件 3.学习视…

MATLAB和西门子SMART PLC OPC通信

西门子S7-200SMART PLC OPC软件的下载和使用,请查看下面文章 Smart 200PLC PC Access SMART OPC通信_基于pc access smart的opc通信_RXXW_Dor的博客-CSDN博客文章浏览阅读2.7k次,点赞2次,收藏5次。OPC是一种利用微软COM/DCOM技术达成自动控制的协议,采用典型的C/S模式,针…

测试用例设计——WEB通用测试用例

现在项目做完了&#xff0c;我觉得还是有必要总结一下&#xff0c;学习到的内容。毕竟有总结才能有提高嘛&#xff01;总结一下通用的东西&#xff0c;不管什么项目基本都可能会遇到&#xff0c;有写地方也有重复的或者有的是按照个人的习惯来总结的不一定都对&#xff0c;有不…

Visual Components Robotics OLP解决方案 北京衡祖

Visual Components 引入了“Visual Components Robotics OLP”的重大升级&#xff0c;合并了制造模拟和机器人离线编程。该解决方案利用 Delfoi Robotics 的技术&#xff0c;提高生产率、减少停机时间并减少浪费。 一、探索下一代离线机器人编程软件 自 1999 年以来&#xff0…

【计算机网络】应用层

应用层协议原理 客户-服务器体系结构&#xff1a; 特点&#xff1a;客户之间不能直接通信&#xff1b;服务器具有周知的&#xff0c;固定的地址&#xff0c;该地址称为IP地址。 配备大量主机的数据中心常被用于创建强大的虚拟服务器&#xff1b;P2P体系结构&#xff1a; 特点&…

详解IPD需求分析工具$APPEALS

够让企业生存下去的是客户&#xff0c;所以&#xff0c;众多企业提出要“以客户为中心”&#xff0c;那如何做到以客户为中心&#xff1f;IPD中给出的答案是需求管理。 需求管理流程&#xff0c;是IPD&#xff08;集成管理开发&#xff09;体系中的四大支撑流程之一&#xff0…

使用Dockerfile生成docker自定义镜像

Dockerfile常用指令 • FROM 构建镜像基于哪个镜像 • MAINTAINER 镜像维护者姓名或邮箱地址 • RUN 构建镜像时运行的指令,执行一条RUN镜像就会叠加一层&#xff0c;因此RUN尽可能一条写完 • ADD 拷贝文件或目录到容器中&#xff0c;如果是URL或压缩包便会自动下载或自动解压…

[2016-2018]phpstudy的exp制作

[2016-2018]phpstudy的exp制作 用python的requests模块进行编写 修改请求数据包进行远程代码执行 import requests import base64 def remove_code_execute():try:url input("请输入要测试的网址:")cmd input("想要执行的命令:")cmd f"system({…

Powercli批量修改分布式交换机端口组

背景 需求&#xff1a; 批量修改虚拟机的分布式端口组 解决方式一&#xff1a; 三条命令解决&#xff1a;先获取目标虚拟机、获取目标端口组、修改虚拟机端口组、检查虚拟机状态。 $vm Get-VM -Name <虚拟机名称> $portGroup Get-VirtualPortGroup -Name <端口…

使用QEMU模拟启动uboot

uboot的相关知识&#xff0c;可以参考&#xff1a;uboot基本概念。 一、环境配置 WSL: ubutu20.04 模拟开发板&#xff1a;vexpress-a9 uboot版本&#xff1a;u-boot-2023.10 二、安装QEMU 2.1、安装sudo apt install qemu2.2、查看支持哪些开发板qemu-system-arm -M help结…

STM32基本定时器中断

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、STM32定时器的结构&#xff1f;1. 51定时器的结构1.1如何实现定时1s的功能&#xff1f; 2. stm32定时器的结构2.1 通用定时器 二、使用步骤1.开启时钟2.初始…