如果实现不同的帐号登陆系统后能看到不同的页面,同一页面也可以设置按钮的权限是否展示?来我带你认识一下RBAC

1.RBAC权限设计思想

背景

为了达成不同的帐号登陆系统后能看到不同的页面,能执行不同的功能的目标,我们有很多种解决方案,RBAC(Role-Based Access control)权限模型 ,也就是基于角色的权限分配解决方案。

其权限模式如下:

三个关键点:

用户: 就是使用系统的人(员工)

权限点:这个系统中有多少个功能(例始:有3个页面,每个页面上的有不同的操作)

角色:不同的权限点的集合

如何给用户添加功能

给用户分配角色,给角色分配权限点

系统中的权限点可以随意添加吗?

不能。必须是程序员已经开发出来的功能!!

一、权限应用:动态生成左侧菜单栏的菜单(利用addRoutes()方法)

思路:当用户点击登录以后,首先进入路由守卫,在路由守卫中,获取用户的信息包括用户权限,在vuex中保存菜单信息,然后运用addRoutes()方法动态添加路由配置,最后完成登录功能,然后用户就可以看到在自己权限范围内显示的页面和功能

补充:addRourtes()对象的格式

router.addRoutes([路由配置对象])
或者:
this.$router.addRoutes([路由配置对象])


 动态添加路由配置

(1)首先要把router文件夹里面添加的动态路由的配置删除掉

const createRouter = () =>
  new Router({
    // 控制路由滚动行为,滚动到顶部
    // mode: 'history', // require service support
    scrollBehavior: () => ({ y: 0 }),
    // 最终生成的路由配置:动态+静态
   - // routes: [...constantRoutes, ...asyncRoutes]
   + routes: [...constantRoutes]
  })


(2)在路由守卫中在有token时,使用addRourtes(),添加动态路由

router.beforeEach(async (to, from, next) => {
  const token = store.state.user.token
  // console.log(token)
  if (token) {
    if (to.path === '/login') {
      // 有token ,还去登录——>直接去主页
      next('/')
    } else {
      if (!store.getters.userId) {
        await store.dispatch('user/getProfile')
        // 通过assRoutes添加用户可以访问的页面
        // 过滤掉没有权限的页面
        const menus = store.state.user.userInfo.roles.menus
        const filterRouters = asyncRoutes.filter(item => {
          return menus.includes(item.children[0].name)
        })
        router.addRoutes(filterRouters)
      
      } 
        next()
      
      
    }


(3)这样配置的动态路由后,会遇到一个问题就是,在地址栏输入地址可以访问对应的页面,但是在菜单栏看不到动态路由

原因分析:当前的菜单渲染使用的数据:this.$router.options.routes 这个数据是固定,我们通过addRoutes添加的路由表只存在内存中,并不会改变this.$router.options.routes

解决这个问题的办法,在vuex中保存静态路由和动态路由

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


然后提交setMenuList生成完整的菜单数据,修改导航守卫中的代码

router.beforeEach(async (to, from, next) => {
  const token = store.state.user.token
  // console.log(token)
  if (token) {
    if (to.path === '/login') {
      // 有token ,还去登录——>直接去主页
      next('/')
    } else {
      if (!store.getters.userId) {
        await store.dispatch('user/getProfile')
        // 通过assRoutes添加用户可以访问的页面
        // 过滤掉没有权限的页面
        const menus = store.state.user.userInfo.roles.menus
        const filterRouters = asyncRoutes.filter(item => {
          return menus.includes(item.children[0].name)
        })
         // 保存到vuex
       + store.commit('menus/setMenuList', filterRouters)
        router.addRoutes(filterRouters)
      
      } 
        next()
      
      
    }


同时,还要修改菜单生成部分改写使用vuex中的数据

routes() {
  // 拿到的是一个完整的包含了静态路由和动态路由的数据结构
- // return this.$router.options.routes
+ return this.$store.state.menu.menuList
}


(4)这样设置动态路由以后页面仍然存在一些bug

1、bug1:一刷新页面白屏的bug

解决bug的方案:把404页改到路由配置的最末尾就可以了

从route/index.js中的静态路由中删除 path:'*'这一项 
 
// 不需要特殊的权限控制就可以访问的页面

export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
// 404 page must be placed at the end !!!
- { path: '*', redirect: '/404', hidden: true }
]
在permission.js中补充在最后

router.beforeEach(async (to, from, next) => {
  const token = store.state.user.token
  // console.log(token)
  if (token) {
    if (to.path === '/login') {
      // 有token ,还去登录——>直接去主页
      next('/')
    } else {
      if (!store.getters.userId) {
        await store.dispatch('user/getProfile')
        // 通过assRoutes添加用户可以访问的页面
        // 过滤掉没有权限的页面
        const menus = store.state.user.userInfo.roles.menus
        const filterRouters = asyncRoutes.filter(item => {
          return menus.includes(item.children[0].name)
        })
      + // 把404添加到最后面
        const page404 = { path: '*', redirect: '/404', hidden: true }
        filterRouters.push(page404)
         // 保存到vuex
        store.commit('menus/setMenuList', filterRouters)
        router.addRoutes(filterRouters)
     + next({
          ...to,
          replace: true
        })
      
      } else{
         next()
      }
          
    }


2、bug2:退出后,再次登陆,发现菜单异常 (控制台有输出说路由重复);

原因
路由设置是通过router.addRoutes(filterRoutes)来添加的,退出时,并没有清空,再次登陆,又加了一次,所以有重复。

需要将路由权限重置 (恢复默认) 将来登录后再次追加才可以,不然的话,就会重复添加

 解决方案:在router/index.js文件,有一个重置路由方法resetRouter(),这个方法就是将路由重新实例化,相当于换了一个新的路由,之前加的路由就不存在了,需要在登出的时候, 调用一下即可,所以,在在store/modules/user.js中调用这个方法

import { resetRouter } from '@/router/index.js'
// 清空信息
    async userLogout(store) {
      // console.log(res)
      // 清除token
      store.commit('removeToken')
      // 清除用户信息
      store.commit('setUserInfo', {})
      resetRouter()
    },


权限应用-按钮级控制(主要就是自定义指令的使用)

前提:后台返回的数据中point中是对按钮的权限,如果binding.vue是在points数组中说明就是有这个权限;

可以通过自定义指令实现按钮级的控制

(1)实现方案一:在main.js中自定义指令

// 自定义指令
Vue.directive('allow', {
  // inserted被绑定的元素插入dom时自动执行
  inserted: function(el, binding) {
    // el dom对象
    const points = store.state.user.userInfo.roles.points
    if (points.includes(binding.value)) {
      // console.log(binding.value)
      // 显示展示元素
    } else {
      // 不显示元素(不安全)
      // el.style.display = 'none'
      // 不要有这个元素,销毁掉元素
      el.parentNode.removeChild(el)
    }
  }
})


在页面的按钮就可以使用v-allow指令,从而根据角色的权限不同从而实现按钮的显示或隐藏

<el-button v-allow="'export_excel'" type="danger" size="small">导出excel</el-button>

(2)实现方案一:利用v-if

  <el-button v-if="$store.state.user.userInfo.roles.points.includes('import_excel')"
          type="warning size="small">导入excel</el-button>

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值