vue管理系统权限控制模块

业务背景

开发后端管理系统要点就是权限控制和安全性

一切从登录开始

从用户想进入管理系统输入账户和密码,然后发送到后端进行账户和密码的正确性验证,如果账户和密码正确,后端就会返回一个独一无二的属于该用户的token,这个时候我们要做的就是把token存起来,存到cookie、session、localStorage、vuex看自己的需求,我这里根据项目要求存到是vuex,vuex配合的是sessionStorage来保持页面刷新不丢失vuex中的数据

使用token换取用户信息

后端的设计一般都是有了token之后在调用获取用户信息接口来拿到登录者的相关信息,比如登录名,头像,对于后端管理系统,还有权限信息列表,这个是后面做权限控制的主要依据

开始权限控制-vue-router的导航守卫

  • 方案一:

获取到权限列表之后,计算出对应权限的路由组成路由表,然后使用router.addRoutes()动态挂载路由,参考自花裤衩https://juejin.im/post/591aa14f570c35006961acac

使用这个方案带来的问题就是如果用户刷新浏览器,保存在vuex甚至保存在sessionStorage和localStorage都会失效,失效原因是在用户刷新页面的时候,vue整个程序程序加载,重新执行了main.js这样的话router也被初始化了,初始化成了那些不需要权限的页面路由,但是我们的也可以在main.js再次检测需要权限的路由,重新使用addRouters添加动态路由,但是会报一个路由命名重复的警告,可是我代码逻辑有问题,这个bug我解决不了就找了公司大佬,大佬给我方案二的思路

  • 方案二

直接在路由配置文件的时候就把所有需要权限的页面使用路由meta属性写好,然后在main.js加载的时候判断是否有权限进入改页面,不使用addRouter动态添加,这样就能保证即使用户刷新页面,router初始化的时候也把所有路由初始化好了,我们只需要在导航守卫的回掉函数里面进行权限鉴定即可,而且这个守卫权限鉴定是全局的,只要有路由变化,都会进行权限鉴定

main.js文件

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './vuex/store'
import '@/reqConfig/index.js'
import token from '@/reqConfig/token.js'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import '@/assets/reset.css'

Vue.use(ElementUI)

Vue.config.productionTip = false

// [skip 跳转登录页面]
function skip () {
  // 异常退出清理session和token
  sessionStorage.clear()
  token.clearToken()
  window.location.href = process.env.VUE_APP_LOGOUT_URL
}

// 全局路由导航守卫
router.beforeEach((to, from, next) => {
  let userInfo = store.state.userinfo.userInfo
  if (userInfo) {
    if (userInfo.account_available) {
      let roles = userInfo.permissions
      // 判断该用户是否有权限进入页面
      if (to.meta.role) {
        let isHasPermission = to.meta.role.every(item => {
          return roles.includes(item)
        })
        if (isHasPermission) {
          next()
        } else {
          ElementUI.Message.error('暂无权限访问该页面,请于管理人员联系')
        }
      } else {
        next()
      }
    } else {
      ElementUI.Message({
        type: 'error',
        message: '暂无权限访问该系统,请于管理人员联系',
        onClose: function () {
          skip()
        }
      })
    }
  } else {
    let key = sessionStorage.getItem('sso-token')
    if (!key) {
      skip()
    } else {
      store.dispatch('getXStreamId').then(() => {
        store.dispatch('getUserInfo').then(res => {
          userInfo = store.state.userinfo.userInfo
          if (userInfo.account_available) {
            let roles = userInfo.permissions
            // 判断该用户是否有权限进入页面
            if (to.meta.role) {
              let isHasPermission = to.meta.role.every(item => {
                return roles.includes(item)
              })
              if (isHasPermission) {
                next()
              } else {
                ElementUI.Message.error('暂无权限访问该页面,请于管理人员联系')
              }
            } else {
              next()
            }
          } else {
            ElementUI.Message({
              type: 'error',
              message: '暂无权限访问该系统,请于管理人员联系',
              onClose: function () {
                skip()
              }
            })
          }
        })
      }).catch(() => {
        skip()
      })
    }
  }
})

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

路由配置文件

import Vue from 'vue'
import Router from 'vue-router'
import A from '@/views/A.vue'
import B from '@/views/B.vue'
import C from '@/views/C.vue'
import D from '@/views/D.vue'

Vue.use(Router)

export const routerMap = [
  {
    path: '/',
    name: 'A',
    component: A
  },
  {
    path: '/b',
    name: 'B',
    component: B,
    meta: { role: ['权限标志字段,比如需要是admin才能访问'] }
  },
  {
    path: '/c',
    name: 'C',
    component: C,
    meta: { role: [权限标志字段,比如需要是super admin才能访问] }
  },
  {
    path: '/d',
    name: 'D',
    component: D,
    meta: { role: [权限标志字段,比如需要是boss才能访问] }
  }
]

export default new Router({
  routes: routerMap
})

猜你喜欢

转载自blog.csdn.net/weixin_32682577/article/details/87516359