vue权限管理浅讲

210 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

权限管理

权限管理就是对每一个操作进行权限限制,比如超级管理员可以添加后台用户、禁用后台用户等

1-1.基本介绍

路由访问权:

不同的用户登录进后台的时候能够访问的路由是不同的,拥有的菜单也是不同的

按钮操作权:

不同的用户都可以访问同一个页面,但是他 们在这个页面里的操作权限却是不同的

思路分析:

前端有一份动态路由表,等到用户登录拿到用户的角色之后根据当前登录用户的角色去筛选出可以访问的路由,形成一份定制路由表,然后动态挂载路由

image.png

1-2.页面访问权(路由)

在当前项目应用用户的页面访问权限

实现步骤

1.在跳转到首页前(前置守卫),拿到用户所拥有的所有菜单权限

数据格式一般如下:

image.png

2.上面得到得到了用户所拥有的菜单名,根据菜单名筛选动态路由并返回

以路由模块的**name**属性命名和权限标识来筛选,这样只要标识能对上,就说明用户拥有了该权限

image.png

// 导入静态路由与动态路由
import { constantRoutes, asyncRoutes } from '@/router'

const state = () => {
  return {
    // 定制路由表(静态加动态)
    routes: constantRoutes
  }
}

const mutations = {
  // 改变路由表,合并动态路由表与静态路由表
  setRouters(state, otherRouters) {
    state.routes = [...constantRoutes, ...otherRouters]
  }
}
const actions = {
  // 筛选当前用户所拥有的 动态权限路由表
  getOtherRoutes(context, menus) {
    const otherRouters = asyncRoutes.filter(item => {
      return menus.includes(item.children[0].name)
    })
	
	// 通过mutation合并路由表
    context.commit('setRouters', otherRouters)
    // 返回动态路由表
    return otherRouters
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

3.拿到动态路由表后,动态挂载路由

// 导入router
import router from '@/router'
// 导入 store
import store from '@/store'

// 导入进度条
import NProgress from 'nprogress' // 引入一份进度条插件
import 'nprogress/nprogress.css' // 引入进度条样式

// 设置白名单
const whiteList = ['/login', '/404']

// 前置守卫
router.beforeEach(async(to, from, next) => {
  // 动画启动
  NProgress.start()
  if (store.getters.token) {
    // 有token
    if (to.path === '/login') {
      next('/')
      NProgress.done()
    } else {
      // 当有信息的时候,就不请求数据了
      if (!store.state.user.userInfo.userId) {
+      // 这里拿到用户的信息,后端必须提供角色所拥有的权限菜单列表(vuex中记得return)
+        const { roles } = await store.dispatch('user/getUseProfile')
		
	   // 调用store/permission中action方法,得到动态路由表(记得加await)
+        const otherRouters = await store.dispatch('permission/getOtherRoutes',      roles.menus)
		// router的原型有一个addRoutes方法,可以动态添加路由
+       router.addRoutes([...otherRouters, { path: '*', redirect: '/404', hidden: true +          }])
+        next({
+          ...to,
+          replace: true
+        })
      }
      next()
    }
  } else {
    // 是否在白名单中
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next('/login')
      NProgress.done()
    }
  }
})

// 后置守卫,停止动画
router.afterEach((to, from) => {
  NProgress.done()
})

注意bug点

1.刷新出现404

产生原因: 先走静态,再走动态====按照顺序走,会先满足* 所以就重定向到了404页面

解决方法: 不要把404页面放在静态路由中,和动态路由一起加进去,保证404页面在最后面

router.addRoutes([...otherRouters, { path: '*', redirect: '/404', hidden: true}])

2.白屏

产生原因: 因为动态路由是后来添加的,直接刷新会出现找不到

解决方法:再进一次路由,刚进来时路由还没铺好,再进来时就好了

next({
 	...to,  // 再进一次要去的页面
 	replace: true // 重进一次, 不保留重复历史
  })
动态渲染菜单

此时用户所拥有的动态路由已经配好了,通过导航栏也能访问,但左侧菜单栏不显示,原因是左侧菜单读取的是固定的路由,我们要把它换成实时的最新路由

image.png

在**src/store/getters.js**配置导出routes

image.png

在左侧菜单组件中, 引入routes

  computed: {
    ...mapGetters([      'sidebar',       'routes'    ]),
退出时重置路由

当我们高级管理员登出操作之后,其他低权限的用户登录,虽然看不到菜单,却能通过导航栏访问高权限的路由

原因分析:

这是因为我们前面在addRoutes的时候,一直都是在,登出的时候,我们并没有删,也没有重置,也就是说,我们之前加的路由在登出之后一直在

解决方案: 用户登出时,路由也需要重置

1.router/index.js文件,有已经封装好的一个重置路由方法

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

2.按需导入到store/user.js下,并调用该方法

import { resetRouter } from '@/router'

  // 同时清除token与userInfo
  logout(context) {
    context.commit('removeToken')
    context.commit('removeUserInfo')
    // 重置路由
    resetRouter()
  }

1-3.按钮操作权

当我们拥有了一个模块的访问权限之后,页面中的某些功能,用户可能有,也可能没有

登录时获取到用户所有的按钮操作权限,有权限则显示,无权限隐藏按钮或者禁用按钮

image.png

方案一:自定义指令

1.定义自定义指令

export const checkbtn = {
  inserted(el, binging) {
    // 拿到getters中的roles
    const roles = store.getters.roles
    // 如果有 且 该员工中没有此权限 , 就隐藏该按钮
    if (roles && !roles.points.includes(binging.value)) {
      el.style.display = 'none'
    }
  }
}

2.组件中使用

image.png

方案二: 使用 Mixins 将检查方法注入

1.下载mixin

yarn add mixin

2.定义混入的对象

一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项

创建文件**src/mixin/checkPermission.js**

import store from '@/store'
export default {
  methods: {
    checkPermission(key) {
      const roles = store.getters.roles
      if (roles && roles.points.includes(key)) {
        return true
      } else {
        return false
      }
    }
  }
}

3.全局混入

在main.js下全局注册

// 全局导入mixin
import checkPermission from '@/mixin/checkPermission'
Vue.mixin(checkPermission)

混入后所有组件的methods中都有一个函数 checkPermission 来检查权限

4.组件中使用

image.png