VUE菜单权限、路由权限、按钮权限控制

8,067 阅读3分钟

大大小小做过不少的后台系统,从登录权限到路由权限等等。在项目中也有遇到遇到很多问题,在此就菜单权限以及路由权限进行总结。

方式1(路由钩子函数里判断)

前端定义路由,配置好路由表,代码示例

{
        path: '/path', 
        component: () => import('./component'),
        name: 'componentName',
        meta: {
            menuName:'菜单名称'
            auth: 'authCode'
        }
    } 
    

在登录的时候后台会返回一串有权限的代码codeList,将这个codeList和本地路由进行相对比,筛选出对应的权限路由,并保存到本地。菜单结构和路由表结构保持一致,路由表既是菜单结构,从而渲染。 在路由钩子函数判断用户是否具有路由meta所标注的authCode,没有权限则跳到事先定义好的界面

缺点

  • 每次跳转都要做权限判断
  • 菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译,并且发版本
  • 菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,有时候路由不一定要作为菜单展示,需要另外加字段不方便

方式2(使用addRoutes挂载路由)

路由权限

前端定义路由,配置好路由表,代码示例

{
        path: '/path', 
        component: () => import('./component'),
        name: 'componentName',
        meta: {
            menuName:'菜单名称'
            auth: 'authCode'
        }
    } 

在登录的时候后台会返回一串有权限的代码codeList,将这个codeList和本地路由进行相对比,筛选出对应的权限路由,并保存到本地。由此生成对应的路由表。在路由钩子函数中使用add.Routes实现路由动态添加,并实现相对应的判断。注意的是{ path: '*', redirect: '/404' }必须放在最后一位,否则会覆盖。代码示例

router.beforeEach((to, from, next) => {
    if (['/login'].includes(to.path)) {
		store.commit('publicModule/SET_ROUTEHAVE', false)
		removeMenu('menuList');
		next();
	} else if (token) {
		if (!store.state.publicModule.routerHave) {
		    //生成后匹配权限的路由表
			var routers = constantRouterMap();
			if (!routers) {
				store.commit('publicModule/SET_ROUTEHAVE', true)
				return next('/no-premission')
			}
			store.commit('publicModule/SET_MENUS', routers)
			store.commit('publicModule/SET_ROUTEHAVE', true)
			router.addRoutes(routers)
			return next({ ...to, replace: true });
		} else {
			next()
		}
	} else {
		next({ path: '/login' });
	}
});

菜单权限

这种方式的菜单是根据我们匹配出来的路由表生成,并渲染的(当然,结构需要保持一致)

缺点

  • 菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译,并且发版本
  • 菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,有时候路由不一定要作为菜单展示,需要另外加字段不方便

方式三

菜单权限

登录的时候后端就返回菜单,进到主界面的时候就进行了渲染。

路由权限 前端配置一个key-value格式的路由表

const componentName = () => import("/path-component-name");
export default {
  componentName
};

后端约定返回:

    {
        name: "componentName",
        path: "/componentName",
        component: "componentName"
      },

后端返回了路由的时候,通过addRoutes动态挂载之间,将数据处理一下(将component字段替换成我们需要的组件,myCOnfig[component]如此)

优点

感觉就前端来说相对省事一点,只要渲染就行了,不需要进行匹配。菜单顺序、标题、图标也都可配置,如果需要进行修改,也不需要前端修改并发包。

按钮权限

后台系统中所对应的按钮,如增删改等权限,我们也是在登录中返回的auth。前端中写了一个指令,如下

import Vue from 'vue'
let action = function(el, binding, vnode) {
    const { value } = binding
    const premissionList = JSON.parse(localStorage.getItem('userAuths')) || [];
    
    if (value) {
        const permissions = value.split(',');
        
        const hasPermission = permissions.some(cur => premissionList.includes(cur))

        if (!hasPermission) {
            el.parentNode && el.parentNode.removeChild(el)
        }
    } 
}
const premission = Vue.directive('limit', {
    inserted(el, binding, vnode) {
        action(el, binding, vnode)
    },
    update(el, binding, vnode) {
        action(el, binding, vnode)
    },
})


export default premission

在页面中使用:

 <el-button
        type="primary"
        @click="handleDelete"
        v-limit="'CONSOLE_AGENT_DRUG_DELETE'"
        ><i class="el-icon-delete el-icon--left"></i>删除</el-button>