RBAC详解

权限设置

1. 权限点

  • 权限: 在一个系统内是否具有做某个操作的权利

  • 权限分成两个级别:

    • 菜单权限: 是否有权限访问某个菜单
    • 按钮权限: 是否有权限操作页面上的某个按钮功能

2. 业务逻辑

  • 对于权限数据来说, 有两个级别的设置

  • 能不能访问某个页面

  • 在页面上,能不能操作某个按钮

3. RBAC权限设计思想(Role-Based Access control)

  • 目标: 不同账号登录系统后看到不同的页面, 能执行不同的功能

  • 权限模式
    在这里插入图片描述

  • 三个关键点:

    1. 用户: 使用系统的人
    2. 权限点: 这个系统中有多少功能(例如: 有3个页面, 每个页面上有不同的操作)
    3. 角色: 不同的权限点的集合
  • 关系:

    1. 给用户分配角色
    2. 给角色分配权限点
    3. 用户和角色是1对多的关系, 一个用户可以拥有多个角色
  • 实际业务中:

    1. 先给员工分配一个具体的角色
    2. 给角色分配具体的权限点

    4.权限点业务

    • 整体分析
      在这里插入图片描述
  • 示例
    在这里插入图片描述

  • 用户在点击登录后, 进行路由跳转之前, 在路由前置守卫中获取用户信息, 将动态路由改成动态添加的方式(router.addRoutes()),菜单项使用的渲染数据项是 this.$router.options.routes , 它只能获取路由表中静态配置的部分 , 而 addRoutes()添加的部分获取不到

  • 因为 this.$router.options.routes 的数据不是响应式的 , 所以即使有了数据也不会反应到视图上

  • 如果调用router.addRoutes() , 想要数据反映到视图上, 需要将路由信息存在vuex中
    在这里插入图片描述

  • 在vuex中定义菜单数据
    在src/store/modules下补充menu.js :

// 导入静态路由
import { constantRoutes } from '@/router'
export default {
  namespaced: true,
  state: {
    // 先以静态路由作为菜单数据的初始值
    menuList: [...constantRoutes]
  },
  mutations: {
    setMenuList(state, asyncRoutes) {
      // 将动态路由和静态路由组合起来
      state.menuList = [...constantRoutes, ...asyncRoutes]
    }
  }
}

在src/store/index.js中注册这个模块

  • 提交setMenuList
    修改src/permission.js
if (!store.getters.userId) {
    await store.dispatch('user/getUserInfo')
    // 把动态路由数据交给菜单
    store.commit('menu/setMenuList', asyncRoutes)
    // 把动态路由添加到应用的路由系统里
    router.addRoutes(asyncRoutes)
}
  • 菜单生成部分该写使用vuex中的数据
    : 该项目使用vue-elment-admin进行二次开发(生成动态侧边栏具体参考vue-elment-admin源码)
routes() {
  // 拿到的是一个完整的包含了静态路由和动态路由的数据结构
  // return this.$router.options.routes
  return this.$store.state.routeMenu.menuList
}
  • 权限数据做过滤处理

    1. 通过后台返回的权限数据, 过滤出要显示的菜单, 过滤使用路由的name作为标识

    2. 从action中获取返回值
      action本质上是一个promise 它的return 结果可以通过const res = await action名来接收
      在这里插入图片描述

    3. 修改 store/modules/user.js

      // 用来获取用户信息的action
          async getUserInfo(context) {
            // 1. ajax获取基本信息,包含用户id
            const rs = await getUserInfoApi()
            console.log('用来获取用户信息的,', rs)
            // 2. 根据用户id(rs.data.userId)再发请求,获取详情(包含头像)
            const info = await getUserDetailById(rs.data.userId)
            console.log('获取详情', info.data)
            // 把上边获取的两份合并在一起,保存到vuex中
            context.commit('setUserInfo', { ...info.data, ...rs.data })
            return rs.data.roles.menus
          },
      
  • 在promise做过滤

if (!store.getters.userId) {
        // 有token,要去的不是login,就直接放行
        // 进一步获取用户信息
        // 发ajax---派发action来做
        const menus = await store.dispatch('user/getUserInfo')
        console.log('当前用户能访问的页面', menus)
        console.log('当前系统功能中提供的所有的动态路由页面是', asyncRoutes)
        // 根据本用户实际的权限menus去 asyncRoutes 中做过滤,选出本用户能访问的页面

        const filterRoutes = asyncRoutes.filter(route => {
          const routeName = route.children[0].name
          return menus.includes(routeName)
        })

        // 一定要在进入主页之前去获取用户信息

        // addRoutes用来动态添加路由配置
        // 只有在这里设置了补充了路由配置,才可能去访问页面
        // 它们不会出现左侧
        router.addRoutes(filterRoutes)

        // 把它们保存在vuex中,在src\layout\components\Sidebar\index.vue
        // 生成左侧菜单时,也应该去vuex中拿
        store.commit('menu/setMenuList', filterRoutes)

        // 解决刷新出现的白屏bug
        next({
          ...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
          replace: true // 重进一次, 不保留重复历史
        })
      }
  • 解决404问题
    原因:现在我们的路由设置中的404页处在中间位置而不是所有路由的末尾了
    解决办法:把404页改到路由配置的最末尾就可以了
    1. 从route/index.js中的静态路由中删除path:’*'这一项
    2. 在permission.js中补充在最后
  • 代码示例:
 // 把404加到最后一条
 filterRoutes.push( // 404 page must be placed at the end !!!
 { path: '*', redirect: '/404', hidden: true })
  • 退出时重置路由
    router/index.js中

    // 重置路由
    export function resetRouter() {
      const newRouter = createRouter()
      router.matcher = newRouter.matcher // 重新设置路由的可匹配路径
    }
    

    这个方法就是将路由重新实例化,相当于换了一个新的路由,之前加的路由就不存在了,需要在登出的时候, 调用一下即可
    store/modules/user.js

    import { resetRouter } from '@/router'
    // 退出的action操作
    logout(context) {
      // 1. 移除vuex个人信息
      context.commit('removeUserInfo')
      // 2. 移除token信息
      context.commit('removeToken')
      // 3. 重置路由
       resetRouter()
      // 4. 重置 vuex 中的路由信息 只保留每个用户都一样的静态路由数据
      //    在moudules中的一个module中去调用另一个modules中的mutation要加{root:true}
      //context.commit('menus/setMenuList', [], { root: true })
    }
    
  • 权限应用 - 控制操作按钮

    在这里插入图片描述

  • 定义全局检测方法
    在main.js中

    Vue.prototype.$checkPoint = function(pointKey) {
      if (store.state.user.userInfo.roles.points) {
        // 进行权限点判断
        return store.state.user.userInfo.roles.points.includes(pointKey)
      }
      // 没有权限点POINTS信息, 说明用户没有身份, 没有任何权限
      return false
    }
    
// 在模板中通过if控制按钮显示
<template>
  <div class="dashboard-container">
    <div class="app-container">
      <el-card>
        <el-button v-if="$checkPoint('CKGZ')">查看工资</el-button>
      </el-card>
    </div>
  </div>
</template>

注: $checkPoint中的参数以系统中权限点的标识符为准

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值