基于RBAC模型的权限设计:如何设计系统权限体系? | 人人都是产品经理
一,什么是RBAC
RBAC(基于角色的权限控制)模型的核心是在用户和权限之间引入了角色的概念。取消了用户和权限的直接关联,改为通过用户关联角色、角色关联权限的方法来间接地赋予用户权限(如下图),从而达到用户和权限解耦的目的。
RBAC的好处
- 职能划分更谨慎。对于角色的权限调整不仅仅只影响单个用户,而是会影响关联此角色的所有用户,管理员下发/回收权限会更为谨慎;
- 便于权限管理。对于批量的用户权限调整,只需调整用户关联的角色权限即可,无需对每一个用户都进行权限调整,既大幅提升权限调整的效率,又降低漏调权限的概率;
在不断的发展过程中,RBAC也因不同的需求而演化出了不同的版本,目前主要有以下几个版本:
1.RBAC0,这是RBAC的初始形态,也是最原始、最简单的RBAC版本;
2.RBAC1,基于RBAC0的优化,增加了角色的分层(即: 子角色),子角色可以继承父角色的所有权限;
3.RBAC2,基于RBAC0的另一种优化,增加了对角色的一些限制: 角色互斥、角色容量等;
4.RBAC3,最复杂也是最全面的RBAC模型,它在RBAC0的基础上,将RBAC1和RBAC2中的优化部分进行了整合;
RBAC1:
RBAC2:
RBAC3:
二、权限管理
一套后台管理系统中基础与核心的板块主要包括: RBAC权限管理模块
RBAC (Role-Based Access Control) : 基于角色的访问控制
系统中包含了用户、角色、权限三个部分,是不是能够不要有“角色”环节? 是可以的,但是不合适
首先需要有一个用户的概念,用户对应的是角色:
- 一个用户可以拥有多个角色 (用户1: 角色N) ,表现形式就是checkbox
- 一个角色可以分配给多个用户 (角色1: 用户N) ,表现形式就是checkbox
- 用户与角色之间的最终对应关系应该是N: N也就是多对多的关系
角色能够做的事情是什么? 角色想对什么东西进行控制? 控制的是什么内容?(角色主要想控制“资源”)
在对角色进行权限分配的时候,出现了一个tree组件,也就是树形菜单,而这个树形菜单中的内容是什么呢?
1. 资源的内容其实主要包括: 菜单(不同的用户看到的菜单就是不一样的) 、按钮(不同的用户在同一个页面中拥有的按钮操作权限也是不一样的)、数据(当前项目没有做)
2. 资源对应于当前项目中,其实就是对应于已经开发的功能版块(菜单)和版块中对应的操作按钮
3. 资源: 已经开发的资源(权限管理、商品管理) 和未开发的资源(订单、客户、优惠券、学生...)
- 对于已经开发的资源可以进行资源的分配,包括菜单、按钮功能的分配,然后让用户拥有这个角色以后,这样的话角色就拥有了这些资源的操作权限
- 对于未开发的资源,如果进行了开发的操作,包括路由的创建、页面的构建、公共组件的设置...那么用户、角色的操作将会受到完全的影响,因为需要给角色和用户进行重新的权限分配操作,而这些角色将重新分配到不同的权限资源。
权限管理主要划分成:
- 菜单级 (所有项目都应用到了,100%)
- 按钮级 (还有一部分项目没有应用到)
- 数据级 (暂时处理不了,实际项目中,如果是中小型项目,应用面也很少)
三、权限管理操作的过程
如果进行登录操作,涉及的是用户、角色、权限三者当中的哪部分工作?
当进行用户登录操作的时候,后端往往会返回前端什么样的数据内容?因为后端需要明确的是该用户拥有什么样的角色,能够进行哪些的权限操作。
- login用户进行登录的时候,后端将返回token令牌,明确用户是可以进行后台操作的,但是没有告诉你,你能操作的是什么。
- info用户信息获取的操作是在login登录以后处理的,因为得先获取到token的令牌,然后呢,需要明确info返回的数据有哪些?
- roles: 角色的意思,一个用户可以拥有N个角色,所以它是数组类型
- routes: 路由的概念,但是给角色设置权限利用的是tree组件,而tree组件中包含的是checkbox复选,说明产生的选中内容是多个,因此会形成数组的结果值,那么这些值将会对应到routes数组当中。现在的routes虽然也是数组,单词仍旧是路由的意思,但是它和实现路由跳转的router中的routes是不一样的。因为实现跳转的routes中包含有name、 path、component、meta等内容,而现在的routes仅仅是一些字符串。
- 后端返回的routes字符串数组: 目的是利用这个数组去对比前端定义的router对应的routes路由,明确哪些是可以进行显示操作的。
- 前端定义的router对应的routes路由: 它主要实现两个功能,一个是菜单的显示,一个是路由的跳转
- 3.buttons: 是为了明确指定模块 (页面中的按钮是否能够起作用,按钮级权限控制是直接写在页面的代码中的,所以是“硬编码”模式。所以就决定了buttons数组中的内容是不能随便修改的。
四、强化用户登录的时候routes和buttons数据的功能与算法
路由菜单权限的基础操作
- 首先routes数组是由谁提供的? 显然是后端提供的。说明的问题是,权限控制需要前端和后台的配合。(因为权限是变化的,不同的用户有不同的角色,不同的角色有不同的权限)
- 路由表:是谁定义的?谁编写的?是静态的还是动态的?前端定义的,前端编写的。之前我们一直讲的是静态路由。后来讲vue3路由的时候我们强化了addRoute、removeRoute,动态添加、动态删除路由。
- 基本算法:其实就是两个数组的比较,但是因为前端路由是可以实现嵌套的,这就意味着会存在递归的问题。
按钮权限的基础操作
- 这个buttons数组是由谁提供的? 显然是后端提供的。说明的问题是,权限控制需要前端和后台的配合。(变化)
- 页面中的按钮是固定的还是变化的? 是固定的。所以按钮是否可用(是否显示)采用的条件判断是使用“硬编码”模式。
- 基本算法: 只需要将一个字符串去数组中进行查找判断,buttons.index0f("btn.trademark.add")
五、路由的分类
src/router/routes.ts是什么文件? 显然它是前端项目路由的配置文件。之前一直强调实现的是静态路由表的配置操作。
路由的分类划分成了:静态路由、动态路由、任意路由
- 静态路由staticRoutes: 是否所有的用户都可以看到一个页面叫login登录页? 是否所有的用户在输入地址错误以后都会看到一个404出错页? 是否所有用户登录系统以后都会看到一个首页? 是的。(静态路由 =>> 所有人都可以操作的路由,是不变化的路由,因此称为静态路由)
- 动态路由allAsyncRoutes: 如果商品管理下包含商品分类、品牌管理、属性管理、SPU管理、SKU管理等众多的页面,但是这些页面是否应该交给不同的人员进行操作,也就是说并不是所有人都能够看到这些页面操作这些页面?后续可能还会有订单下面的订单查询,优惠券下面的优惠券清单等类似的模块与页面。那么这些页面的操作是不定人员,是自由分配与动态管理的。所以,这些类似商品管理的内容的菜单和按钮应该是后台后回数据并且动态生成的! (动态路由 =>> 只有指定人员才能查看与跳转的路由)
- 任意路由anyRoute: 如果用户输入地址错误,一般都会显示一个404页面,而这个页面的路由设置都是在所有路由的最后,它也是固定的,唯一的,也是不变的。(任意路由 =>> 只有一个404页面的路由配置)
// 静态路由(默认路由)
export const staticRoutes: Array<RouteRecordRaw> = [
{
path: "/login",
name: "Login",
component: () => import('@/views/login/index.vue'),
meta:{
hidden: true,
}
},
.
.
.
];
// 定义动态路由(异步路由)
export const allAsyncRoutes: Array<RouteRecordRaw> = [
// 产品模块
{
path: "/product",
name: "Product",
component: () => import('@/layout/index.vue'),
meta:{
title: "商品管理",
icon: "ele-ShoppingBag"
},
children:[]
},
// 新闻模块
// 订单模块
// 促销模块
// 物流模块
.
.
.
];
// 任意路由
export const anyRoute=
/*匹配任意的路由必须最后注册*/
{
path:"/:pathMatch(.*)",
name:"Any",
redirect:"/404",
meta: {
hidden: true,
},
}
问题: 最终项目里的routes路由请问有几个? 只有1个!!!
最终staticRoutes、allAsyncRoutes、anyRoute需要进行一次整合、拼接,最终合成一个路由数组对象。最后发现staticRoutes、anyRoute都是不变化的,而allAsyncRoutes是可能会随着系统功能的扩展,从而产生变化,所以后续主要操作的就是allAsyncRoutes。