vue框架搭建权限管理
思路:利用vuex,动态添加路由。
实现:在用户登录时,获取用户身份信息,接口返回该用户所对应的权限菜单,前端匹配并动态添加路由。
细节:
一、编写前端路由:
登录页面路由以及404页面为固定页面所以路由无需动态加载,将这一部分的路由起名为:
******router.js*******
export const constantRouterMap = [
{path: '/login', component: () => import('@/views/login/index'), hidden: true},
{path: '/404', component: () => import('@/views/404'), hidden: true},
{
path: '',
component: Layout,
redirect: '/home',
children: [{
path: 'home',
name: 'home',
component: () => import('@/views/home/index'),
meta: {title: '首页', icon: 'home'}
}]
}
]
而其他路由需要动态引用所以额外导出为:
export const asyncRouterMap = [
{
path: '/home',
name: 'Home',
components:{
content:() => import(/* webpackChunkName: "about" */ '../views/Home.vue'),
header: () => import('../components/layout/Layout.vue'),
slider:() => import('../components/Header.vue'),
},
meta: { title: '首页' }
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
components:{
content:() => import(/* webpackChunkName: "about" */ '../views/About.vue'),
header: () => import('../components/layout/Layout.vue'),
slider:() => import('../components/Header.vue'),
},
meta: { title: '关于' }
},
]
二、创建状态管理器
结构如上图所示
在permission中做出路由权限判断:
import { asyncRouterMap, constantRouterMap } from '@/router/index';
//判断是否有权限访问该菜单
function hasPermission(menus, route) {
if (route.name) {
let currMenu = getMenu(route.name, menus);
if (currMenu!=null) {
//设置菜单的标题、图标和可见性
if (currMenu.title != null && currMenu.title !== '') {
route.meta.title = currMenu.title;
}
if (currMenu.icon != null && currMenu.title !== '') {
route.meta.icon = currMenu.icon;
}
if(currMenu.hidden!=null){
route.hidden = currMenu.hidden !== 0;
}
if (currMenu.sort != null && currMenu.sort !== '') {
route.sort = currMenu.sort;
}
return true;
} else {
route.sort = 0;
if (route.hidden !== undefined && route.hidden === true) {
return true;
} else {
return false;
}
}
} else {
return true
}
}
//根据路由名称获取菜单
function getMenu(name, menus) {
for (let i = 0; i < menus.length; i++) {
let menu = menus[i];
if (name===menu.name) {
return menu;
}
}
return null;
}
//对菜单进行排序
function sortRouters(accessedRouters) {
for (let i = 0; i < accessedRouters.length; i++) {
let router = accessedRouters[i];
if(router.children && router.children.length > 0){
router.children.sort(compare("sort"));
}
}
accessedRouters.sort(compare("sort"));
}
//降序比较函数
function compare(p){
return function(m,n){
let a = m[p];
let b = n[p];
return b - a;
}
}
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers;
state.routers = constantRouterMap.concat(routers);
}
},
actions: {
GenerateRoutes({ commit }, data) {
return new Promise(resolve => {
const { menus } = data;
const { username } = data;
const accessedRouters = asyncRouterMap.filter(v => {
//admin帐号直接返回所有菜单
// if(username==='admin') return true;
if (hasPermission(menus, v)) {
if (v.children && v.children.length > 0) {
v.children = v.children.filter(child => {
if (hasPermission(menus, child)) {
return child
}
return false;
});
return v
} else {
return v
}
}
return false;
});
//对菜单进行排序
sortRouters(accessedRouters);
commit('SET_ROUTERS', accessedRouters);
resolve();
})
}
}
};
export default permission;
在main.js中写入动态添加方法与请求用户信息
main.js
import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { Message } from 'element-ui'
// import { getToken } from '@/utils/auth' // 验权
const whiteList = ['/login'] // 不重定向白名单
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
if (to.path === '/login') {
next({ path: '/' })
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
} else {
if (store.getters.roles.length === 0) {
store.dispatch('GetInfo').then(res => { // 拉取用户信息
let menus=res.data.menus;
let username=res.data.username;
store.dispatch('GenerateRoutes', { menus,username }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
next({ ...to, replace: true })
})
}).catch((err) => {
store.dispatch('FedLogOut').then(() => {
Message.error(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
next()
}
}
} else
{
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next('/login')
NProgress.done()
}
}
next()
})
router.afterEach(() => {
NProgress.done() // 结束Progress
})