1. 介绍
在任何企业级应用中,尤其是后台管理系统,权限控制是一个至关重要的环节。它确保了系统资源的安全性,防止非法访问和操作,保障业务流程的正常进行。本文件将详细解析后台管理系统中的权限控制机制及其实施策略。
那么权限控制都包括什么呢?
- 页面权限:菜单栏是否显示,路由是否可访问
- 功能权限:按钮是否显示,是否可点击
- 接口权限:接口是否可访问(后端内容)
不同的账号显示的菜单栏不同,页面上可以操作的按钮也不一样,这些操作都是通过权限模型实现的,那么接下来我们就来学习下常见的权限模型
2. 常见权限模型
- 基于角色的访问控制(Role-Based Access Control, RBAC)
- 在RBAC模型中,权限不直接授予用户 ,而是首先定义 一系列角色 ,然后将权限分配给这些角色 。用户通过成为某个或多个角色的成员来获取对应的权限。这种模型简化了权限管理,因为它允许管理员集中管理角色而不是逐个管理用户。角色可以按组织结构、职责或者工作流进行划分。
- 自主访问控制(Discretionary Access Control, DAC)
- 在DAC模型中,资源的所有者可以自行决定谁可以访问该资源。用户可以自由地将其所控制的信息或资源的访问权限转让给其他用户。操作系统中的文件权限设置就是一个典型的DAC实例,用户可以设置文件的读、写、执行权限给其他用户或用户组。
- 强制访问控制(Mandatory Access Control, MAC)
- MAC是一种严格的安全策略,其中系统本身负责所有权限决策,不允许用户随意更改。权限级别是由系统内定的安全策略决定,通常是基于信息的敏感性和用户的安全许可级别。在这种模型下,即使资源所有者也不能随意更改权限设置。
- 基于属性的访问控制(Attribute-Based Access Control, ABAC)
- ABAC模型基于用户、资源、环境和操作的多种属性来决定访问权限。权限决策基于多重属性组合,例如用户的身份、位置、时间以及操作上下文等多种因素。这种方式更为灵活和精细,可以支持复杂的动态权限策略。
- 基于任务的访问控制(Task-Based Access Control, TBAC)
- TBAC关注的是完成特定任务所需的最小权限集。用户在执行特定任务时获得必要的权限,任务完成后权限则会被收回。
- 基于能力的访问控制(Capability-Based Access Control, CBAC)
- 在CBAC模型中,访问控制基于"能力"这一概念,能力是表示对某一资源具有特定访问权限的令牌。用户拥有一个或多个能力令牌,持有令牌意味着有权访问相应的资源。
3. RBAC(角色的访问控制模型)
- RBAC 模型的基本思想是将用户和权限分离,通过角色作为中间层来连接用户和权限。一个角色可以关联多个权限,一个用户可以拥有多个角色。这样可以实现灵活的权限配置和管理,避免直接给用户分配权限带来的复杂性和冗余性。
- RBAC 模型有多个扩展版本,如 RBAC0、RBAC1、RBAC2 等。我们使用的是 RBAC0 模型,即最基本的 RBAC 模型。RBAC0 模型包含三个要素:用户(User)、角色(Role)和权限(Permission)。用户是指使用系统的主体,角色是指一组相关的权限的集合,权限是指对系统资源的访问或操作能力。
- 从上图中我们可以梳理出来的业务,就有,用户管理,角色管理,权限管理(有的系统中是菜单管理,后续给大家分析两者的差异)。所以我们在这里最少可以拆分出三张表,即用户,角色,权限,当然因为用户和角色,角色和权限都是多对多的关系,我们还可以有两张中间表,即总共5张表,但是在很多情况下,我们并没有反查的需求,所以3张表的设计是够用的。
4. vue3中实现权限控制方案
4.1. 分析
页面权限 的核心是 路由表配置,路由表分为两部分:
- 固定路由表(constantRoutes):每个角色都有的路由表,例如登录界面、404界面
- 私有路由表(privateRoutes):不同角色拥有不同的路由表
实现 页面权限 我们有两种方式:
- 前端复杂版:即后端只返回当前用户的权限数据,前端根据权限数据,清洗路由后,再将清洗剩下的路由动态添加到路由表中。 (推荐)
- 后端复杂版:我们将所有私有路由都放到后端,在登录时,后端将当前用户的路由返回给我们(这里的路由也是我们的菜单数据,因为菜单和路由是关联的,也有的项目中是将路由和菜单分开,这里不探讨这种实现),这也就是上面说到的有的项目中会有个菜单管理的原因。
前端复杂方案:
优点:1. 后端只需关注rbac模型的核心,即用户,角色,权限。不需要关心我们的菜单标题,图标等。2. 我们可以在前端随时调整我们的项目视图文件路径。3. 路由元数据配置更方便。
缺点:修改菜单后,需要前端发版。
后端复杂方案:
优点:1. 可以直接在数据库中调整菜单标题,图标等。2. 可支持用户在界面配置菜单选项
缺点:1. 需要增加菜单管理功能。2. 适用项目模板的人,必须对后端有一定了解。3. 前端目录结构受限,必须与后端返回的数据一致。
推荐前端复杂方案:1. 我们即使有了菜单管理功能,当他新增一个菜单,我们前端一样需要新增对象文件。2. 菜单的顺序,图标,标题让用户自己修改的概率不大。3. 逻辑性更清晰。
4.2. 实现页面控制
4.2.1. 获取权限数据(省略了部分其余代码)
javascript
export const useUserStore = defineStore('user', () => {
// ...
const permissions = ref<Ipermissions>([])
// ...
// 获取权限
function getPermissions() {
return permissionApi().then((res) => {
permissions.value = res.result.permissions
return permissions.value
})
}
// ...
return { permissions, getPermission }
}, {
persist: {
key: `${STORAGE_PREFIX}${USER}`,
paths: ['token', 'userInfo'],
storage: localStorage,
},
})
mock的后端返回数据
4.2.2. 在我们的路由上新增我们的权限字段auth
auth类型如下
在元信息中加入我们auth
4.2.3. 清洗路由
- 利用 addRoute API 动态的将路由添加到路由表中
4.3. 实现按钮权限
在vue中,他给我们提供了指令功能
所以我们可以封装一个权限指令,来解决我们的按钮权限
使用
处理这样,我们还可以吧这个封装成一个权限组件
使用
5. react18中实现权限控制方案
5.1. 分析
和vue一致,不赘述
5.2. 实现页面控制
5.2.1. 获取权限数据
mock的后端返回数据
5.2.2. 在我们的路由上新增我们的权限字段auth
auth类型如下
在元信息中加入我们auth
5.2.3. 权限控制
react-router中,他并没有给我们提供动态添加路由的方案,但是由于react非常灵活,所以以前我们是自己实现的动态添加路由,但是在最新的react-router版本中,他推荐使用最新的路由创建方式
但是这种方案,会导致我们很难动态的添加路由,所以采用的把所有路由都注入到路由表中,在路由进入的时候,判断权限,没权限的跳转403的方案。
5.3. 实现按钮权限
react中是没有像vue那样给我们提供自定义指令功能的,但是我们完全可以自己封装一个权限按钮组件。
6. 完整项目
6.1. vue3
github:github.com/1245488569/...
6.2. react18
github:github.com/1245488569/...