RBAC 基础 -权限控制
RBAC 角色权限控制
1. 什么是 RBAC
RBAC(Role-Based Access Control,基于角色的访问控制),是一种新的访问控制机制, 它是以角色为中心来进行访问控制的,即用户通过角色与权限进行关联,进而获得权限,从而访问系统资源。
什么是ABAC(扩展--->框架少,实现比较困难,开发成本高,但一旦实现,可以实现很多复杂的控制)
ABAC(Attribute-Based Access Control,基于属性的访问控制),是一种新的访问控制机制, 它是以属性为中心来进行访问控制的,即用户通过属性与权限进行关联,进而获得权限,从而访问系统资源。
2. RBAC 的优点
RBAC 的优点主要有以下几点:
- 降低了复杂性:
- 降低了维护成本
- 降低了风险:
- 降低了开发成本
- 降低了运维成本
- 降低了安全风险
- 降低了系统复杂度
- 降低了系统的耦合度
- 降低了系统的依赖性
3. RBAC 的分级
- RBAC0:基本的RBAC模型,只有用户、角色、权限三个基本元素,是最简单的RBAC模型。
- RBAC1:在RBAC0的基础上增加了角色继承,即角色可以继承其他角色的权限。
- RBAC2:在RBAC1的基础上增加了用户-角色绑定,即用户可以绑定多个角色。
- RBAC3:在RBAC2的基础上增加了约束,即角色可以绑定多个用户,但是每个用户对于某个角色的绑定都有时间上的限制。
3. RABC 的核心
- 用户(User):用户是指系统的使用者,可以是一个人,也可以是一台机器,或者其他什么东西。
- 角色(Role):角色是指用户的职责或者角色,一个用户可以有多个角色,一个角色可以包含多个用户。
- 权限(Permission):权限是指用户在某个角色上可以执行的操作,一个角色可以包含多个权限,一个权限可以包含多个角色。
- 资源(Resource):资源是指用户可以访问的系统资源,比如文件、目录、数据库等。
- 操作(Operation):操作是指用户对资源可以执行的操作,比如读、写、执行等。
- 会话(Session):会话是指用户在一段时间内的访问,一般来说,用户登录系统后,就会建立一个会话,直到用户退出系统,这个过程就是一个会话。
- 会话管理(Session Management):会话管理是指对用户的会话进行管理,包括建立会话、维护会话、销毁会话等。
- 会话控制(Session Control):会话控制是指对用户的会话进行控制,包括会话的访问控制、会话的权限控制等。
- 会话访问控制(Session Access Control):会话访问控制是指对用户的会话进行访问控制,包括会话的访问控制、会话的权限控制等。
- 会话权限控制(Session Permission Control):会话权限控制是指对用户的会话进行权限控制,包括会话的访问控制、会话的权限控制等。
- 会话权限管理(Session Permission Management):会话权限管理是指对用户的会话进行权限管理,包括会话的访问控制、会话的权限控制等。
- 会话权限分配(Session Permission Assignment):会话权限分配是指对用户的会话进行权限分配,包括会话的访问控制、会话的权限控制等。
4. RBAC 的实现
RBAC 系统
1. 基于角色控制资源访问
2. 数据库表设计 :
用户表--->用户角色中间--->角色表--->角色资源中间表--->资源表
3. 前后端构建
1.1 基于Vue 快速构建
1.2 使用Element-Ui 快速渲染页面布局
1.3 spring-boot 快速构建web 项目
4. 前后端数据交互
1.1.1 构建表格页面
-
基本CURD 的数据交互
1.2.2 基本实现分页数据展示--->获取当前分页条的数据--->发送Axios请求 拿去分页数据
---> 后端接搜数据 ---> 查询全部信息(涉及时间的字段使用@JsonFromat(....)),通过分页插件PageHelper,将list集合封装到PageInfo中,返回JsonResult
1.2.2 实现基本删除 ----->点击删除按钮,通过插槽 scope,获取到当前行的数据---> 发送Axios 请求 --->后端接受到当前行的id(主键iD)-->执行删除SQL 语句
1.2.3 实现批量删除的方法 ---> 勾选时,给定状态,当点击批量删除时,遍历该状态的行,拿去取主键ID存入集合,发送Psot请求,将数组通过qs.tistringify方法(设置不需要数组索引)将书据转换成json格式,设置发送方式将数据转换成表单(www---???),----> 后端接受数据List<>,或数组都可以(使用@RequestParam 接收)--->拿到数组,执行SQL语句,通过动态SQL 遍历传过来的数组,执行数据的删除.
1.2.3 实现新增功能 -->点击新增按钮弹出新增表单,输入数据,点击提交时--->发送Axios请求,将表单数据提交到后端处理-->后端拿到对应的实体类对象数据--->执行新增SQL语句(设置时间可以使用NOW() )
1.2.4 实现并编辑功能-->点击编辑,回显数据,拿到当前行的全部数据-->发送Axios请求把实体类对象传入后端--->后端接受参数,执行修改的SQL语句(动态SQL if 判断字段)
1.2.5 在分页功能的基础上增加过滤查询,动态sql 判断
-
树形结构数据
1.1 动态菜单查询
1.1.1 遍历
▼java复制代码1. 思路: 遍历方式用于获取树形结构数据中的每一个节点,通常使用迭代方法来实现。 2. 代码逻辑: - 初始化一个队列或栈,将根节点加入其中。 - 进入循环,直到队列或栈为空。 - 在每次迭代中,弹出队列或栈中的一个节点,处理它的数据。 - 如果节点有子节点,将子节点加入队列或栈,以便后续处理。1.1.2 递归调用
▼java复制代码1. 思路: 递归方式用于获取树形结构数据中的每一个节点,通常使用递归方法来实现。 2. 代码逻辑: - 创建一个递归函数,接受当前节点作为参数。 - 在递归函数中,处理当前节点的数据。 - 如果当前节点有子节点,对每个子节点调用递归函数。 - 递归会一直深入子节点,直到到达叶子节点。1.1.3 sqL 语句
▼sql复制代码<!-- 循环的 SQL --> SELECT * FROM menu WHERE parent_id = 0; -- 获取根节点 <!-- 递归的 SQL --> WITH RECURSIVE MenuTree AS ( SELECT * FROM menu WHERE parent_id = 0 -- 获取根节点 UNION ALL SELECT m.* FROM menu m INNER JOIN MenuTree mt ON m.parent_id = mt.id ) SELECT * FROM MenuTree; -- 递归查询的 SQL 使用了公共表达式(CTE)和 UNION ALL,以获取所有层级的子菜单。 -
穿梭框 数据交互 查询 分配角色--->用户_角色表
1.1 前端页面
1.2 拿取所有角色
1.3 通过分配按钮拿去当前用户id 查询所拥有的角色
1.4 判断用户是否更改过穿梭框的数据,校验是否有数据---有--->拿到当前表数据,发送请求--->后端接受请求获取参数-->拿到 用户ID 先执行删除角色的Sql --->删除成功后新增角色数据(先删后改--->保证事务的一致性)
-
角色分配权限 角色表_权限中间表 -->权限表
0 --> 页面加载时获取 所有权限
1.1 前端点击分配按钮 --->弹出表单数据
1.2 发送 请求查询当前拥有的权限--->SQL 查询-->回显数据
1.3 修改后提交--->拿到表单数据,发送请求--->后端接受请求获取参数,拿到 角色ID 先执行删除已有权限的Sql --->删除成功后新增表单权限数据(先删后改--->保证事务的一致性)
-
登陆相关权限验证
-
登录
1.前端页面提交表单数据--->发送请求
2.后端接受请求,检查数据是否正常
3.正常:查询SQL 拿取对应的user信息,判断数据是否和前端传过来的一致
4:一致:用UUID生成Token,调用Spring-boot中Redis(RedisTemplate.opsForValue().set())方法,以Token为key,对象为value存入Redis中(对应实体类应支持序列化)
5.返回Token
6.前端接受数据,VueX将数据存入请求头
7.立即调用Info 方法,根据Token获取对应的用户信息
-
获取信息
1.VueX调用Info 方法,根据Vuex中存入的Token获取对应的用户信息
2.后端接受请求,从请求头中获取Token(@RequestHeader)
3.校验数据,有没有传Token,有,判断Token是否有效
4.从Redis中获取用户信息(RedisTemplate.opsForValue().get())
5.将数据返还后端
-
登出
- 点击退出登录按钮发送登出请求
- 后端接受到请求,从请求头中获取Token
- 拿到Token,调用RedisTemplate.delet()方法
- 返回成功的状态信息
- 前端Vuex接受成功响应,从前端重置Token,刷新页面
-
5.请求拦截器
-
判断登录请求拦截器
1.自定义登录拦截器,继承HandlerInterceptorAdapter或实现HandlerInterceptor (交给容器管理)
2.实现preHandle
3.逻辑判断处理
▼java复制代码1.获取请求头中的Token 2.根据Token去Redis中查询对应的用户信息 3.有信息,放行 没有拦截4.将自定义拦截器注册到Spring-Mvc 中
5.编写 WebMvcConfigurer 配置类,实现
▼java复制代码// 注册拦截器 registry.addInterceptor(checkLoginInterceptor) // 将自定义拦截器注入到mvc中 .addPathPatterns("/**") // 设置需要拦截的路径 /** 表示拦截所有请求 .excludePathPatterns("/users/login"); // 设置排除的路径 登录请求不需要拦截 -
访问资源权限请求拦截器
1.定义注解,贴在方法上来解释该方法请求的资源对应需要的权限
2.自定义拦截器
3.逻辑判断处理
3.1 是否是超级管理员权限
▼java复制代码1.获取请求头中的Token 2.根据Token去Redis中查询对应的用户信息 3.是管理员,可以访问所有路径,放行
3.2 判断用户访问的资源是否需要权限
▼java复制代码1.获取访问资源的路径方法 HandlerMethod handlerMethod = (HandlerMethod) handler; 2获取方法上的注解 handlerMethod.getMethodAnnotation(RequiredPermission.class); //传入自定义注解字节码通过反射获取value值 3.如果拿不到该注解,说明不需要权限,直接放行
3.3 判断该用户是否具有该注解的对应数据
▼java复制代码1.通过用户id 关联 用户和角色中间表 2.再通过角色id 关联 角色和权限中间表 3.再同过权限id 查询 对应的权限表达式 4. 一个用户可能会有多个权限 ,且权限可能重复(去重) 5.拿到权限表达式集合判断是否包含当前访问资源的权限 6.有.放行 没有 : 拦截
6. 优化逻辑
-
常量类抽取: 对常用字符串,数字等抽取
-
自定义异常:在代码中,如出现逻辑判断会抛出一些异常,如果用RuntimeException(),Exception都会难以快速定位
-
统一异常处理:将异常统一处理不用在可能出现异常的代码上都使用tar catch 包围,还可以指定自定义异常的处理方式
-
方法抽取:将一些多次使用的代码抽离出来定义成工具类,增加复用性

