1.vuex中定义一个用户状态,roles储存当前登录用户的权限
写一个存储roles的mutations
mutations: {
SET_ROLES: (state, roles) => {
state.roles = roles
}
},
2.登录时,查询用户的状态,再将权限状态存储。写一个ations
// 获取用户信息
actions:{
GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => {
// getUserInfo 获取用户信息接口
getUserInfo(state.token).then(response => {
if (!response.data) {
reject('error')
}
const data = response.data
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', data.roles) // 此处储存权限
} else {
reject('getInfo: roles must be a non-null array !')
}
resolve(response)
}).catch(error => {
reject(error)
})
})
},
}
3. 在router中编写公共路由表(constantRouterMap)和动态路由表(asyncRouterMap),利用route中的meta属性储存该路由的权限信息
例:
export const constantRouterMap = [
{ path: '/login', component: () => import('@/views/login/index'), hidden: true },
{ path: '/404', component: () => import('@/views/errorPage/404'), hidden: true },
{ path: '/401', component: () => import('@/views/errorPage/401'), hidden: true },
]
// account路由权限 ['super-admin', 'admin'],/account/account-admin路由权限['admin']
export const asyncRouterMap = [
{
path: '/account',
meta: { roles: ['super-admin', 'admin'] },
children: [
{ path: '/account-admin', component: () => import('组件路径'), name: 'account', meta: { roles: ['admin'] } },
]
},
]
4. vuex中编写权限处理permission.js
// 导入 公共和动态路由表
import { asyncRouterMap, constantRouterMap } from '@/router'
/**
* 通过meta.role判断是否与当前用户权限匹配
* @param roles
* @param route
*/
// 判断当前路由中的权限 route.meta.roles 是否包括登录用户的权限
// 例 该/account路由权限['super-admin', 'admin'] 登录用户为['admin'] 返回true
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.indexOf(role) >= 0)
} else {
return true
}
}
/**
* 递归过滤异步路由表,返回符合用户角色权限的路由表
* @param asyncRouterMap
* @param roles 当前登录的用户权限 格式例:['admin']
*/
function filterAsyncRouter(asyncRouterMap, roles) {
const accessedRouters = asyncRouterMap.filter(route => {
if (hasPermission(roles, route)) {
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, roles)
}
return true
}
return false
})
return accessedRouters
}
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 { roles } = data
let accessedRouters
// 超级管理员拥有所有权限 直接合并公共路由和动态路由表
if (roles.indexOf('super-admin') >= 0) {
accessedRouters = asyncRouterMap
} else {
accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
}
commit('SET_ROUTERS', accessedRouters)
resolve()
})
}
}
}
export default permission
5. 在main.js同级目录创建一个权限处理js
import router from './router'
import store from './store'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'// progress bar style
import { getToken } from '@/utils/auth' // getToken from cookie
NProgress.configure({ showSpinner: false })// NProgress Configuration
const whiteList = ['/login', '/bhp']// no redirect whitelist
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
if (getToken()) { // determine if there has token
/* has token*/
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) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 拉取user_info 用户信息
const roles = res.data.roles // note: roles must be a array! such as: ['super-admin','admin']
// 此处调用4中的vuex方法 将用户权限传入
store.dispatch('GenerateRoutes', { roles }).then(() => {
//最终的路由表通过addRoutes,加入到router中
router.addRoutes(store.getters.addRouters)
next({ ...to, replace: true })
})
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
// Message.error(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
next()
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next('/login') // 否则全部重定向到登录页
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
router.afterEach(() => {
NProgress.done() // finish progress bar
})
6.在main.js中导入5中的同级权限js
import './permission' // permission control
7. 在el-menu菜单中,判断动态生成子菜单
此处的routes
来自4中,vuex中permission.js
中的status.routers
,
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<router-link
v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow"
:to="item.path+'/'+item.children[0].path"
:key="item.children[0].name"
>
<el-menu-item
:index="item.path+'/'+item.children[0].path"
:class="{'submenu-title-noDropdown':!isNest}"
>
</el-menu-item>
</router-link>
<el-submenu v-else :index="item.name||item.path" :key="item.name">
<template slot="title">
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
<span v-if="item.meta&&item.meta.title" slot="title">{{generateTitle(item.meta.title)}}</span>
</template>
<template v-for="child in item.children" v-if="!child.hidden">
<sidebar-item
:is-nest="true"
class="nest-menu"
v-if="child.children&&child.children.length>0"
:routes="[child]"
:key="child.path"
></sidebar-item>
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path" @click="clickSideBar">
</el-menu-item>
</router-link>
</template>
</el-submenu>
</template>