第九天学习总结—权限概念

逐字稿

1、RBAC思想是什么

RBAC是Role-Based Access Control四个单词的缩写:意思是基于角色的访问控制。具体理解为:员工拥有角色,给员工分配权限;角色拥有权限,给角色分配权限。 RBAC思想的好处:假设公司来了员工,他有对应的3个权限,若是运用RBAC思想,你只需要分配一个角色即可,否则你需要分配3个权限。所以RBAC思想使得访问管理变得更容易。

2、如何给员工分配角色/给角色分配权限

  • 如何给员工分配角色:
    • 先举例说角色有哪些/哪些权限
      • 角色:系统管理员/人事经理/人事专员/薪资专员/员工
      • 权限:组织架构/角色管理/员工管理/权限管理/审批/考勤/工资/社保
    • 数据回显:这里需要elementui框架里面的el-dialog和多选框组配合使用。当点击角色按钮弹框出现的时候,从封装好的端口获取对应权限的id并放入对应的数组,然后将数组绑定到多选框组v-model绑定的数组里面进行回显展示。
    • 分配角色:获取给用户分配角色的id,并将所获取的id通过封装好的接口发送到后端。
    • 为何不直接给员工分配权限:分配权限很麻烦,但是分配角色就显得很简单
// 回显角色信息
async roleEmployeeMsg(id) {
  this.currentRoleId = id // 赋值当前管理员id
  this.roleIdList = []
  // 打开弹窗
  this.showRoleDialog = true
  // 获取启用角色列表
  this.roleList = await getEnableRoleList()
  // 获取当前员工权限id
  const { roleIds } = await getEmployee(id)
  this.roleIds = roleIds
},
// 确定角色弹窗
async sureRoleDialog() {
  await assingRoles({ id: this.currentRoleId, roleIds: this.roleIds })
  this.$message.success('分配员工角色成功')
  this.showRoleDialog = false
}
  • 给角色分配权限:
    • 数据回显:需要elementui框架里面的el-dialog和el-tree组件。点击分配权限,从封装好的接口获取数据,因为树形组件需要树形数据所以需要将列表数据转为树形数据并将其绑定到el-tree组件里面的data属性达到回显。
    • 分配权限:在点击弹窗确定按钮的时候,我们需要配合el-tree提供的default-checked-keys属性和getCheckedKeys方法获取当前组件所选中的分配的权限id并将其传输到后端。
// 回显分配权限信息
async addPermission(id) {
  this.currentPermissionId = id
  const res = await getPermissionList()
  this.permissionList = translateListToTreeData(res, 0)

  const { permIds } = await getRoleDetailMsg(id)
  this.permIds = permIds
  this.showPermissionDialog = true
},
// 选中权限后确定分配权限
async sureAddAssign() {
  await assignPrem({ id: this.currentPermissionId, permIds: this.$refs.permissionRef.getCheckedKeys() })
  this.$message.success('分配权限成功')
  this.showPermissionDialog = false
}

3、项目中为什么要拆分静态路由和动态路由

我们项目用的是menu菜单实现权限功能的。将静态和动态路由进行拆分这是为了给项目设置访问权限。静态路由所有人都可以访问的,比如首页/登陆/404等待。它是固定的。而动态路由只有有权限的人才可以访问,比如组织/角色/员工/权限等。动态路由是不固定的。动态路由的访问取决于用户角色。我们只有将动态路由抽离与静态路由区分开来,才能实现不同用户根据不同角色获取不同的访问权限这个需求。

4、如何根据权限筛选出动态路由?

这个需求我们放在前置守卫里面处理,首先我们从仓库里面获取token,判断他是否存在,再判断用户是否访问登录界面,不是的话再判断是否能够获取到用户id,没有的话从store中调用用户数据,返回后端提供的menu数据,然后我们通过asyncRoutes配合filter和includes方法获取当前用户拥有的访问权限。接着,将其与404路由通过addRoutes放入router。

if (token) {
    if (to.path === '/login') {
      next('/')
      nProgress.done()// 关闭进度条
    } else {
      if (!store.getters.userId) {
        const { roles } = await store.dispatch('user/updateUserInfo')
        const filterRoutes = asyncRoutes.filter(item => {
          return roles.menus.includes(item.name)
        })
        router.addRoutes([...filterRoutes, { path: '*', redirect: '/404', hidden: true }])
        next(to.path)   //添加动态路由之后,需要转发一下
      } else {
        next()
      }
    }
  } else {
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next('/login')
      nProgress.done()// 关闭进度条
    }
  }
Snipaste\_2023-06-05\_15-59-28.png

5、动态添加路由是如何实现的?

我们正在获取当前用户的menus数据后,通过asyncRoutes配合filter和includes方法获取当前用户拥有的访问权限。接着,将addRoutes放入router。但这有2个问题:1、404需要放入路由的最末端。2、在添加完路由信息之后,需要通过next(to.path)来解决动态路由不显示的问题。

知识点

  • 插槽新旧写法对比

    Snipaste_2023-06-05_10-25-28.png

    Snipaste_2023-06-05_10-53-02.png