设计思想
RBAC的权限模型:RBAC(Role-Based Access control),也就是基于角色的权限分配解决方案 实现的目标:不同权限的员工登录可以有不同的权限数据
分配权限
注册增加一个弹层组件
<template>
<!-- 分配权限的弹层 -->
<el-dialog
title="分配权限(一级为路由页面查看权限-二级为按钮操作权限)"
:visible="showAssignDialog"
>
<!-- 权限点数据展示 -->
<template #footer>
<div style="text-align: right;">
<el-button @click="closeAssignDialog">取消</el-button>
<el-button type="primary">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
export default {
props: {
showAssignDialog: {
type: Boolean,
default: false
}
}
}
</script>
<style>
</style>
添加控制弹层的打开关闭 父传子,子传父 渲染使用el-tree组件
<template>
<!-- 分配权限的弹层 -->
<el-dialog
title="分配权限(一级为路由页面查看权限-二级为按钮操作权限)"
:visible="showAssignDialog"
@close="closeAssignDialog"
@open="openDialog"
>
<el-tree
:data="permissionList"
:props="{ label: 'name' }"
:default-expand-all="true"
:show-checkbox="true"
:check-strictly="true"
node-key="id"
/>
<!-- 权限点数据展示 -->
<template #footer>
<div style="text-align: right;">
<el-button @click="closeAssignDialog">取消</el-button>
<el-button type="primary">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import { getPermissionList } from '@/api/permission'
import transTree from '@/utils/transTree.js'
export default {
props: {
showAssignDialog: {
type: Boolean,
default: false
}
},
data() {
return {
permissionList: []
}
},
methods: {
closeAssignDialog() {
this.$emit('close_dialog')
},
async openDialog() {
const res = await getPermissionList()
this.permissionList = transTree(res.data)
}
}
}
</script>
<style>
</style>
添加权限
使用组件方法
node-key="id"
可以更改获取到的数据属性为id getCheckedKeys()获取到所有选中节点的id
async confirm() {
await assignPerm({
id: this.curId,
permIds: this.$refs.tree.getCheckedKeys()
})
this.$message.success('分配权限成功')
this.closeAssignDialog()
}
数据回显
用到tree组件方法setCheckedKeys,达成数据回显
async openDialog() {
const res = await getPermissionList()
this.permissionList = transTree(res.data)
// 数据回显 调用组件方法
const resd = await getRoleDetailById(this.curId)
this.$refs.tree.setCheckedKeys(resd.data.permIds)
},
分配角色
注册组件 完成弹层的打开和关闭
<template>
<el-dialog class="assign-role" title="分配角色" :visible="showRoleDialog">
<!-- 这里准备复选框 -->
<template #footer>
<el-button type="primary" size="small">确定</el-button>
<el-button size="small">取消</el-button>
</template>
</el-dialog>
</template>
<script>
export default {
props: {
showRoleDialog: {
type: Boolean,
default: false
}
}
}
</script>
获取角色列表 在open事件中 渲染到复选框中 选框组 显示的内容是绑定的选项 如果需要显示别的属性可以使用插值表达式{{}}在里面出来
<template>
<el-dialog
class="assign-role"
title="分配角色"
:visible="showRoleDialog"
@close="closeRoleDialog"
@open="openDialog"
>
<!-- 这里准备复选框 -->
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="item in list" :key="item.id" :label="item.id">{{ item.name }}</el-checkbox>
</el-checkbox-group>
<template #footer>
<el-button type="primary" size="small" @click="confirm">确定</el-button>
<el-button size="small" @click="closeRoleDialog">取消</el-button>
</template>
</el-dialog>
</template>
<script>
import { getRoleListApi } from '@/api/setting'
export default {
props: {
showRoleDialog: {
type: Boolean,
default: false
},
id: {
type: String,
default: ''
}
},
data() {
return {
checkList: [],
list: [],
curId: ''
}
},
methods: {
closeRoleDialog() {
this.$emit('close-dialog')
},
async openDialog() {
const res = await getRoleListApi()
this.list = res.data.rows
// this.curId = this.id
// console.log(this.list)
// 数据回显
},
}
}
</script>
分配功能完善 需要id 和 选中的角色数组 id通过父传子获取
/**
* @description: 为用户分配角色
* @param {*} data { id:当前用户id, roleIds:选中的角色id组成的数组 }
* @return {*}
*/
export function assignRoles(data) {
return request({
url: '/sys/user/assignRoles',
data,
method: 'put'
})
}
async confirm () {
await assignRoles({ id: this.id, roleIds: this.checkList })
this.$message.success('分配角色成功')
// 关闭弹层
this.$emit('close-dialog')
}
数据回显 根据id查询角色信息 将获取到的角色数组赋值个给绑定数组,达到回显
import { getUserInforMationApi } from '@/api/user'
async openDialog() {
const res = await getRoleListApi()
this.list = res.data.rows
// this.curId = this.id
// console.log(this.list)
// 数据回显
const { data } = await getUserInforMationApi(this.id)
this.checkList = data.roleIds
// console.log(data)
},
权限应用
所谓的路由系统浏览器中输入path,可以渲染出来一个对应的component
RBAC权限思想和实际应用RBAC概念
- 基于角色的权限控制思想 流程 用户 角色 权限点三个主体
- 首先给用户分别配角色 然后给角色分配权限点
为什么要进行基于角色的设计
- 最开始用户和权限点 形成多对多的关系杂乱 员工一旦离职 需要把所有的权限解绑 新入一个员工又得把所有的权限点再重新分配一次
- 加入了角色 把权限数据直接都分配给固定的几个角色,新员工入职只需要配置一次权限点和角色关系 任何一个员工进来都可以和酷爱的得到应有的权限
员工管理 + 角色管理 + 权限点管理
- 角色模块是为了员工服务的 给员工分配角色
- 权限点模块是为了角色服务的 给角色分配权限点
路由系统的动态加入
- 得到menus权限数据+ 本地存储的动态完整的路由表
- 以menus为主对动态路由表做过滤筛选
- 调用一个router的实例方法 addRouters 加入路由系统
菜单显示控制
- 解决方法vuex 需要满足
- 动态操作
- 影响视图的渲染
- 多模块共享
- 以静态路由表定义state 以拼写静态+筛选之后的动态作为mutation函数
准备两个数据
获取动态路由表和个人信息
// 路由表
import { asyncRoutes } from '@/router'
// 获取角色信息 这里用的是下面方法的返回值
const res = await store.dispatch('user/getUserInfoAction')
console.log(res)
console.log(asyncRoutes)
过滤
用获得的信息过滤路由
const filterRouters = asyncRoutes.filter(item => menus.includes(item.children[0].name))
加入路由系统
动态路由表 动态添加 将过滤好的路由表加入,让路由可用 将路由配置中的动态路由表删除,将过滤后的路由数组添加到路由系统中 使用addRoutes方法
router.addRoutes(filterRouters)
渲染到左侧菜单
路由渲染的是所有的静态路由 用vuex来保存数据这样就变成了响应式的
import { constantRoutes } from '@/router/index'
export default {
namespaced: true,
state: {
menus: {}
},
mutations: {
setMunes(state, payload) {
state.menus = { ...constantRoutes, ...payload }
}
}
}
store.commit('menu/setMunes', filterRouters)
return this.$store.state.menu.menus
退出登录重置路由
本质上addRouter方法是一个累加的方法 退出登录会执行user/reset_state方法,在方法内重置路由
按钮指令
Vue.directive inserted(el,binding) 指令挂载的元素完成渲染时自动执行的钩子函数
el
:指令绑定的dom元素binding.value
:指令等于好后面的表达式 获取当前的父节点 移除子节点el.parentNode.removeChild(el)