设计思想

RBAC的权限模型:RBAC(Role-Based Access control),也就是基于角色的权限分配解决方案 实现的目标:不同权限的员工登录可以有不同的权限数据

RBAC权限 - 图1

分配权限

注册增加一个弹层组件

  1. <template>
  2. <!-- 分配权限的弹层 -->
  3. <el-dialog
  4. title="分配权限(一级为路由页面查看权限-二级为按钮操作权限)"
  5. :visible="showAssignDialog"
  6. >
  7. <!-- 权限点数据展示 -->
  8. <template #footer>
  9. <div style="text-align: right;">
  10. <el-button @click="closeAssignDialog">取消</el-button>
  11. <el-button type="primary">确定</el-button>
  12. </div>
  13. </template>
  14. </el-dialog>
  15. </template>
  16. <script>
  17. export default {
  18. props: {
  19. showAssignDialog: {
  20. type: Boolean,
  21. default: false
  22. }
  23. }
  24. }
  25. </script>
  26. <style>
  27. </style>

添加控制弹层的打开关闭 父传子,子传父 渲染使用el-tree组件

  1. <template>
  2. <!-- 分配权限的弹层 -->
  3. <el-dialog
  4. title="分配权限(一级为路由页面查看权限-二级为按钮操作权限)"
  5. :visible="showAssignDialog"
  6. @close="closeAssignDialog"
  7. @open="openDialog"
  8. >
  9. <el-tree
  10. :data="permissionList"
  11. :props="{ label: 'name' }"
  12. :default-expand-all="true"
  13. :show-checkbox="true"
  14. :check-strictly="true"
  15. node-key="id"
  16. />
  17. <!-- 权限点数据展示 -->
  18. <template #footer>
  19. <div style="text-align: right;">
  20. <el-button @click="closeAssignDialog">取消</el-button>
  21. <el-button type="primary">确定</el-button>
  22. </div>
  23. </template>
  24. </el-dialog>
  25. </template>
  26. <script>
  27. import { getPermissionList } from '@/api/permission'
  28. import transTree from '@/utils/transTree.js'
  29. export default {
  30. props: {
  31. showAssignDialog: {
  32. type: Boolean,
  33. default: false
  34. }
  35. },
  36. data() {
  37. return {
  38. permissionList: []
  39. }
  40. },
  41. methods: {
  42. closeAssignDialog() {
  43. this.$emit('close_dialog')
  44. },
  45. async openDialog() {
  46. const res = await getPermissionList()
  47. this.permissionList = transTree(res.data)
  48. }
  49. }
  50. }
  51. </script>
  52. <style>
  53. </style>

添加权限

使用组件方法 node-key="id"可以更改获取到的数据属性为id getCheckedKeys()获取到所有选中节点的id

  1. async confirm() {
  2. await assignPerm({
  3. id: this.curId,
  4. permIds: this.$refs.tree.getCheckedKeys()
  5. })
  6. this.$message.success('分配权限成功')
  7. this.closeAssignDialog()
  8. }

数据回显

用到tree组件方法setCheckedKeys,达成数据回显

  1. async openDialog() {
  2. const res = await getPermissionList()
  3. this.permissionList = transTree(res.data)
  4. // 数据回显 调用组件方法
  5. const resd = await getRoleDetailById(this.curId)
  6. this.$refs.tree.setCheckedKeys(resd.data.permIds)
  7. },

分配角色

注册组件 完成弹层的打开和关闭

  1. <template>
  2. <el-dialog class="assign-role" title="分配角色" :visible="showRoleDialog">
  3. <!-- 这里准备复选框 -->
  4. <template #footer>
  5. <el-button type="primary" size="small">确定</el-button>
  6. <el-button size="small">取消</el-button>
  7. </template>
  8. </el-dialog>
  9. </template>
  10. <script>
  11. export default {
  12. props: {
  13. showRoleDialog: {
  14. type: Boolean,
  15. default: false
  16. }
  17. }
  18. }
  19. </script>

获取角色列表 在open事件中 渲染到复选框中 选框组 显示的内容是绑定的选项 如果需要显示别的属性可以使用插值表达式{{}}在里面出来

  1. <template>
  2. <el-dialog
  3. class="assign-role"
  4. title="分配角色"
  5. :visible="showRoleDialog"
  6. @close="closeRoleDialog"
  7. @open="openDialog"
  8. >
  9. <!-- 这里准备复选框 -->
  10. <el-checkbox-group v-model="checkList">
  11. <el-checkbox v-for="item in list" :key="item.id" :label="item.id">{{ item.name }}</el-checkbox>
  12. </el-checkbox-group>
  13. <template #footer>
  14. <el-button type="primary" size="small" @click="confirm">确定</el-button>
  15. <el-button size="small" @click="closeRoleDialog">取消</el-button>
  16. </template>
  17. </el-dialog>
  18. </template>
  19. <script>
  20. import { getRoleListApi } from '@/api/setting'
  21. export default {
  22. props: {
  23. showRoleDialog: {
  24. type: Boolean,
  25. default: false
  26. },
  27. id: {
  28. type: String,
  29. default: ''
  30. }
  31. },
  32. data() {
  33. return {
  34. checkList: [],
  35. list: [],
  36. curId: ''
  37. }
  38. },
  39. methods: {
  40. closeRoleDialog() {
  41. this.$emit('close-dialog')
  42. },
  43. async openDialog() {
  44. const res = await getRoleListApi()
  45. this.list = res.data.rows
  46. // this.curId = this.id
  47. // console.log(this.list)
  48. // 数据回显
  49. },
  50. }
  51. }
  52. </script>

分配功能完善 需要id 和 选中的角色数组 id通过父传子获取

  1. /**
  2. * @description: 为用户分配角色
  3. * @param {*} data { id:当前用户id, roleIds:选中的角色id组成的数组 }
  4. * @return {*}
  5. */
  6. export function assignRoles(data) {
  7. return request({
  8. url: '/sys/user/assignRoles',
  9. data,
  10. method: 'put'
  11. })
  12. }
  1. async confirm () {
  2. await assignRoles({ id: this.id, roleIds: this.checkList })
  3. this.$message.success('分配角色成功')
  4. // 关闭弹层
  5. this.$emit('close-dialog')
  6. }

数据回显 根据id查询角色信息 将获取到的角色数组赋值个给绑定数组,达到回显

  1. import { getUserInforMationApi } from '@/api/user'
  2. async openDialog() {
  3. const res = await getRoleListApi()
  4. this.list = res.data.rows
  5. // this.curId = this.id
  6. // console.log(this.list)
  7. // 数据回显
  8. const { data } = await getUserInforMationApi(this.id)
  9. this.checkList = data.roleIds
  10. // console.log(data)
  11. },

权限应用

image.png

所谓的路由系统浏览器中输入path,可以渲染出来一个对应的component

RBAC权限思想和实际应用RBAC概念

  • 基于角色的权限控制思想 流程 用户 角色 权限点三个主体
  • 首先给用户分别配角色 然后给角色分配权限点

为什么要进行基于角色的设计

  • 最开始用户和权限点 形成多对多的关系杂乱 员工一旦离职 需要把所有的权限解绑 新入一个员工又得把所有的权限点再重新分配一次
  • 加入了角色 把权限数据直接都分配给固定的几个角色,新员工入职只需要配置一次权限点和角色关系 任何一个员工进来都可以和酷爱的得到应有的权限

员工管理 + 角色管理 + 权限点管理

  • 角色模块是为了员工服务的 给员工分配角色
  • 权限点模块是为了角色服务的 给角色分配权限点

路由系统的动态加入

  • 得到menus权限数据+ 本地存储的动态完整的路由表
  • 以menus为主对动态路由表做过滤筛选
  • 调用一个router的实例方法 addRouters 加入路由系统

菜单显示控制

  • 解决方法vuex 需要满足
    • 动态操作
    • 影响视图的渲染
    • 多模块共享
  • 以静态路由表定义state 以拼写静态+筛选之后的动态作为mutation函数

如何在调用完action函数之后拿到函数内部的数据

准备两个数据

获取动态路由表和个人信息

  1. // 路由表
  2. import { asyncRoutes } from '@/router'
  3. // 获取角色信息 这里用的是下面方法的返回值
  4. const res = await store.dispatch('user/getUserInfoAction')
  5. console.log(res)
  6. console.log(asyncRoutes)

过滤

用获得的信息过滤路由

  1. const filterRouters = asyncRoutes.filter(item => menus.includes(item.children[0].name))

加入路由系统

动态路由表 动态添加 将过滤好的路由表加入,让路由可用 将路由配置中的动态路由表删除,将过滤后的路由数组添加到路由系统中 使用addRoutes方法

  1. router.addRoutes(filterRouters)

渲染到左侧菜单

路由渲染的是所有的静态路由 用vuex来保存数据这样就变成了响应式的

  1. import { constantRoutes } from '@/router/index'
  2. export default {
  3. namespaced: true,
  4. state: {
  5. menus: {}
  6. },
  7. mutations: {
  8. setMunes(state, payload) {
  9. state.menus = { ...constantRoutes, ...payload }
  10. }
  11. }
  12. }
  1. store.commit('menu/setMunes', filterRouters)
  1. return this.$store.state.menu.menus

退出登录重置路由

本质上addRouter方法是一个累加的方法 退出登录会执行user/reset_state方法,在方法内重置路由

按钮指令

Vue.directive inserted(el,binding) 指令挂载的元素完成渲染时自动执行的钩子函数 el:指令绑定的dom元素 binding.value:指令等于好后面的表达式 获取当前的父节点 移除子节点 el.parentNode.removeChild(el)