一、背景
为了达成不同的帐号登陆系统后能看到不同的页面,能执行不同的功能
的目标,我们有很多种解决方案,RBAC(Role-Based Access control)权限模型 ,也就是基于角色的权限分配解决方案。
其权限模式如下:
三个关键点:
用户: 就是使用系统的人(员工)
权限点:这个系统中有多少个功能(例始:有3个页面,每个页面上的有不同的操作)
角色:不同的权限点的集合
如何给用户添加功能
给用户分配角色,给角色分配权限点
系统中的权限点可以随意添加吗?
不能。必须是程序员已经开发出来的功能!!
小结
-
RBAC解决什么问题: 不同的人,有不同功能~
-
role-based access control
-
三个主体: 用户 , 角色 , 权限点
二、员工分配角色
背景
目前系统中已经有一些角色,我们下面要将这些角色分配给不同的员工,让他们进入系统后,做不同的事情。
用户和角色是**1对多
**的关系:一个用户可以拥有多个角色,这样他就会具体这多个角色的权限了。比如公司的董事长可以拥有财务主管和保安队长的角色: 董事长可以看财务报表,也可以查看监控。
目前系统中已有的角色:
目标
在员工管理页面中,点击分配角色时,以弹层的方式打开/关闭组件
在员工页面为员工分配角色
点击分配角色按钮
思路
-
把具体的功能给拆分出去(角色的功能比较复杂,拆分组件会减轻工作量)
-
通过弹层控制显示
封装分配角色组件
员工管理同一文件夹下新建assignRole.vue
<template>
<!-- // 分配角色 -->
<div>
<!-- 放置多选列表 -->
<!-- 此处多选框为静态数据,具体的真实项目中,数据一般为后端提供,通过调用接口获取,然后v-for渲染到页面中 -->
/*
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="item in xxList" label="xxx">xxxx</el-checkbox>
</el-checkbox-group>
*/
<el-checkbox-group v-model="checkList">
<el-checkbox label="110">系统管理员</el-checkbox>
<el-checkbox label="111">人事经理</el-checkbox>
<el-checkbox label="112">人事专员</el-checkbox>
<el-checkbox label="113">薪资专员</el-checkbox>
<el-checkbox label="114">员工</el-checkbox>
</el-checkbox-group>
<div style="margin-top: 20px; text-align: right">
<el-button type="primary">确定</el-button>
<el-button @click="closeDialog">取消</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
checkList: [] // 当多选框的某一项为勾选状态时,此项的label值会存在此数组中
}
},
methods: {
closeDialog() { // 点击取消按钮的回调函数
this.$emit('close') // 触发父组件(index.vue)内的close自定义事件,关闭弹窗
}
}
}
</script>
注册并使用组件
在员工管理的主页index.vue
中,引入上面添加的组件
<script>
// 引入组件
import AssignRole from './assignRole'
// 注册组件
export defalut {
data() {
return {
// 省略其他....
dialogVisible: false // 控制dialog组件是否显示
}
},
components: {
// 省略其他....
AssignRole // 注册组件
},
methods: {
hCloseDialog() { // close自定义事件的回调函数,关闭弹窗
this.dialogVisible = false
}
}
}
</script>
// 使用组件
<el-dialog title="分配角色" :visiable.sync="dialogVisible">
<assign-role @close="hCloseDialog"/>
</el-dialog>
实现交互效果
员工管理的主页index.vue
中
操作分配角色按钮,添加点击事件
<el-button type="text" size="small" @click="hAssignRole(id)">分配角色</el-button>
hAssignRole(id) {
console.log('当前要分配角色的id是', id) // 分配角色需要获取id,定位到某一员工,id是唯一值
this.dialogVisible = true // 显示dialog弹框组件,进行后续勾选角色操作
}
显示dialog,进行勾选分配角色
点击确定按钮,完成分配角色
assignRole.vue
组件中
<el-button type="primary" @click="hSubmit">确定</el-button>
hSubmit() {
// 代码...
// 此处把勾选的数组checkList以后端需要的数据形式,通过后端给定的接口传到后端
this.closeDialog() // 调用取消按钮的回调函数,关闭弹窗
}
三、角色分配权限
为什么要给角色分配权限
用户是什么角色(职位),他就具备某些功能
前面的代码中已经给用户加了角色了,那员工到底能做什么事,还是由角色中携带的具体的功能来定的。
权限管理页面功能比较多,需要封装组件。
点击权限管理页面的分配权限按钮,显示所有权限
思路
准备弹框 -> 注册事件 -> 提供数据方法
完成给角色分配权限点的业务
封装分配权限组件
权限管理同一文件夹下新建assignPermission.vue
<template>
<!-- // 分配角色 -->
<div>
<!-- 这里将来会放置多选列表 -->
<el-tree
ref="tree"
:data="permissionsList"
:props="defaultProps"
show-checkbox
default-expand-all
check-strictly
node-key="id"
/>
<div style="margin-top: 20px; text-align: right">
<el-button type="primary">确定</el-button>
<el-button @click="closeDialog">取消</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
permissionsList: [{ // 此处为假数据,真实项目中需调用接口,获取数据,渲染到页面中
label: '员工管理', // 数据回填 this.$refs.tree.setCheckedKeys(真实数据数组),页面就会显示该角色已有的权限,显示为勾选状态
children: [{
label: '测试',
label: '导入excel',
label: '导出excel',
}]
}, {
label: '公司设置',
}, {
label: '权限管理',
}, {
label: '社保',
}, {
label: '审批',
}, {
label: '考勤',
}, {
label: '工资',
}, {
label: '组织架构',
}], //
defaultProps: {
children: 'children',
label: 'label'
}
}
},
methods: {
closeDialog() { // 点击取消按钮的回调函数
this.$emit('close') // 触发父组件(index.vue)内的close自定义事件,关闭弹窗
}
}
}
</script>
注册并使用组件
在权限管理的主页index.vue
中,引入上面添加的组件
<script>
// 引入组件
import AssignPermission from './assignPermission'
// 注册组件
export defalut {
data() {
return {
// 省略其他....
dialogVisible: false // 控制dialog组件是否显示
}
},
components: {
// 省略其他....
AssignPermission // 注册组件
},
methods: {
hCloseDialog() { // close自定义事件的回调函数,关闭弹窗
this.dialogVisible = false
}
}
}
</script>
// 使用组件
<el-dialog title="分配权限" :visiable.sync="dialogVisible">
<assign-permission @close="hCloseDialog"/>
</el-dialog>
实现交互效果
权限管理的主页index.vue
中
操作分配角色按钮,添加点击事件
<el-button type="success" size="small" @click="hAssignPermission(id)">分配权限</el-button>
hAssignPermission(id) {
console.log('当前要分配权限的角色的id是', id) // 分配权限需要获取id,定位到某一角色,id是唯一值
this.dialogVisible = true // 显示dialog弹框组件,进行后续勾选权限点操作
}
显示dialog,进行勾选分配权限
点击确定按钮,完成分配权限
assignPermission.vue
组件中
<el-button type="primary" @click="hSubmit">确定</el-button>
hSubmit() {
// 代码...
// 此处把勾选的权限点数组以后端需要的数据形式,通过后端给定的接口传到后端
// this.$refs.tree.getCheckedKeys() 获取勾选的权限点
this.closeDialog() // 调用取消按钮的回调函数,关闭弹窗
}
四、用户登录后根据角色显示权限页面
到目前为止,我们实现了RBAC权限设计思想的各个环节,我们给员工分配了角色,给角色又分配了权限点,员工现在已经有了相对应的权限点,接下来我们就可以利用这些权限点做实际的权限控制,在类似的人资项目里,权限的控制有两个地方:
- 左侧菜单权限控制(不同的用户进来系统之后,看到的菜单是不同的)
- 操作按钮权限控制 (页面上的按钮,不同的人也有不同权限)
权限数据在哪里
在员工管理页面中新建2个全新的员工数据(张三、李四),然后使用其中一个全新的员工账号登录,查看个人信息接口(后端给定的接口)的返回数据
// 假定数据存在如下数组中
menus: [], // 存放此员工基于管理员分配的角色所能看见的权限页面
points: [] // 存放此员工基于管理员分配的角色所能看见的权限页面内的权限按钮
如何修改权限数据
使用管理员账号登录,然后给刚才创建的新员工分配俩个菜单权限和一个操作按钮权限,然后我们再次登录员工账号查看个人信息返回数据
操作步骤:
-
权限点管理 > 给员工管理下增加
导入excel,导出excel
按钮操作权限点 -
角色管理 > 新建角色人事经理 > 给角色分配权限 (员工管理,导入excel,导出excel)
角色管理 > 新建角色人事专员 > 给角色分配权限 (员工管理) -
员工管理 > 给员工张三分配人事经理角色
员工管理 > 给员工李四分配人事经理角色 -
重新登录新员工账号,查看权限数据,观察menus, points数组内数据
张三
李四
权限应用-动态生成左侧菜单-整体分析
分析
登录成功(页面跳转),进入导航守卫:
- 获取个人权限信息
- 生成可以访问的动态路由
示例
经过数据处理两个员工显示的页面效果图
张三 / 李四
权限应用-按钮级控制
员工A和员工B都可以访问同一个页面(以员工管理为例),但是员工A可以导出excel,员工B就不可以导出excel
由张三和李四的points数组(points: [ ] // 存放此员工基于管理员分配的角色所能看见的权限页面内的权限按钮)看出,虽然两人都可以显示员工页面,但拥有的按钮级别的权限不同
如果某个按钮上的标识在points出现,则可以显示出来(v-if、v–show,控制按钮显示或隐藏)
张三(人事经理)
李四(人事专员)
权限控制流程重点梳理总结
业务场景
公司里有不同的职能部门,都在用同一套系统 ,不一样部门的人员进入系统里面需要操作的事情是不一样的
必定需要根据不同的员工角色配置不同的权限
RBAC权限设计思想
一种基于角色的设计思想
- 给员工配置角色 (一个员工可以拥有多个角色)
- 给角色配置权限点 (一个角色可以有多个权限点)
员工只要有了角色之后,就自动拥有了角色绑定的所有权限点
根据权限设计思想对应业务模块
- 员工管理
- 角色管理
- 权限点管理(它是没有调整的余地的:它会严格与当前系统的功能对应!)
员工得到权限数据
员工信息接口中有当前员工的所有权限数据
menus: [], // 菜单权限数据
points: [] // 按钮权限数据
使用权限数据做具体的权限处理
-
菜单权限控制
登录 > 菜单权限数据 > 和本地的所有的动态路由数据做匹配出具 > 得到根据权限筛选之后的动态路由数据
- 添加到路由系统中 (可以根据路径标识渲染组件 addRoutes)
- 添加到左侧菜单渲染
-
按钮权限控制
登录 > 按钮权限数据 > 使用按钮单独的权限标识 去权限数据里面查找
自定义指令