默認掛載不須要權限的路由,例如:登陸、主頁。須要權限的頁面經過 router.addRoutes(點擊查看官方文檔) 動態添加更多的路由規則,404攔截頁面須要放在路由表的最後,不然 /404 後面的路由會被404攔截,經過路由元信息meta(點擊查看官方文檔)記錄路由須要的權限。爲了菜單列表能夠被翻譯,路由表的 name 屬性值經過 i18n 的英文對照表來獲取,也能夠直接寫英文名稱,如 name: routeNmae.builtInIcon
能夠直接寫成 name: "builtInIcon"
,憑我的喜愛html
// src/router/index.js import en from '../i18n/lang/en' // 路由名字 name import Vue from 'vue' import Router from 'vue-router' import CommerViews from '@/views/commerViews' import Login from '@/views/login/index' import Layout from '@/views/layout/layout' import HomeMain from '@/views/index/mainIndex' // 不是必須加載的組件使用懶加載 const Icon = () => import('@/views/icon/index') const Upload = () => import('@/views/upload/upload') const Markdown = () => import('@/views/markdown/markdownView') const NotFound = () => import('@/page404') Vue.use(Router) let routeNmae = en.routeNmae // 不須要權限的路由 let defaultRouter = [ { path: '/', redirect: '/index', hidden: true, children: [] }, { path: '/login', component: Login, name: '', hidden: true, children: [] }, { path: '/index', iconCls: 'fa fa-dashboard', // 菜單圖標,直接填寫字體圖標的 class name: routeNmae.home, component: Layout, alone: true, children: [ { path: '/index', iconCls: 'fa fa-dashboard', name: '主頁', component: HomeMain, children: [] } ] }, { path: '/404', component: NotFound, name: '404', hidden: true, children: [] }, ] // 須要 addRouters 動態加載的路由 let addRouter = [ { path: '/', iconCls: 'fa fa-server', name: routeNmae.multiDirectory, component: Layout, children: [ { path: '/erji1', iconCls: 'fa fa-server', name: routeNmae['menu2-1'], component: Erji, children: [] }, { path: '/erji3', iconCls: 'fa fa-server', name: routeNmae['menu2-3'], component: CommerViews, // 無限極菜單的容器 超過三級菜單父級容器須要使用 CommerViews children: [ { path: '/sanji2', iconCls: 'fa fa-server', name: routeNmae['menu3-2'], component: Sanji2, children: [] }, { path: '/sanji3', iconCls: 'fa fa-server', name: routeNmae['menu3-3'], component: CommerViews, children: [ { path: '/siji', iconCls: 'fa fa-server', name: routeNmae['menu4-1'], component: Siji, children: [] }, { path: '/siji1', iconCls: 'fa fa-server', name: routeNmae['menu4-2'], component: CommerViews, children: [ { path: '/wuji', iconCls: 'fa fa-server', name: routeNmae['menu5-1'], component: Wuji, children: [] } ] } ] } ] } ] }, { path: '/', iconCls: 'el-icon-edit', // 圖標樣式class name: routeNmae.editor, component: Layout, meta: {role: ['superAdmin', 'admin']}, // 須要權限 'superAdmin', 'admin'。meta屬性能夠放在父級,驗證父級和全部子菜單,也能夠放在子級單獨驗證某一個子菜單 children: [ { path: '/markdown', iconCls: 'fa fa-file-code-o', // 圖標樣式class name: routeNmae.markdown, component: Markdown, children: [] } ] }, { path: '*', redirect: '/404', hidden: true, children: [] }, ] export default new Router({ routes: defaultRouter }) export {defaultRouter, addRouter}
而後經過 token
獲取當前登陸用戶的我的信息,在router
被掛載到Vue以前和須要權限的路由表作對比,篩選出當前角色的動態路由表,vue
// main.js // 獲取角色信息,根據用戶權限動態加載路由 router.beforeEach((to, from, next) => { if (store.getters.token) { // 查看 token 是否存在 store.dispatch('setToken', store.getters.token) // 每次操做都從新寫入 token,延長有效會話時間 if (to.path === '/login') { next({path: '/'}) } else { if (!store.getters.info.role) { // 查看是否有當前用戶角色,若是沒有則獲取角色信息 !async function getAddRouters () { await store.dispatch('getInfo', store.getters.token) // 經過token獲取角色信息 await store.dispatch('newRoutes', store.getters.info.role) // 經過權限篩選新路由表 await router.addRoutes(store.getters.addRouters) // 動態加載新路由表 next({path: '/index'}) }() } else { let is404 = to.matched.some(record => { // 404頁面攔截 if(record.meta.role){ // 沒有權限的頁面,跳轉的404頁面 return record.meta.role.indexOf(store.getters.info.role) === -1 } }) if(is404){ next({path: '/404'}) return false } next() } } } else { if (to.path === '/login') { next() } next({path: '/login'}) } })
// src/vuex/modules/role.js state: { info: '' // 每次刷新都要經過token請求我的信息來篩選動態路由 }, mutations: { getInfo (state, token) { // 省略 axios 請求代碼 經過 token 向後臺請求用戶權限等信息,這裏用假數據賦值 state.info = { role: 'superAdmin', permissions: '超級管理員' } // 將 info 存儲在 sessionStorage裏, 按鈕指令權限將會用到 sessionStorage.setItem('info', JSON.stringify(store.getters.info)) }, setRole (state, options) { // 切換角色,測試權限管理 state.info = { role: options.role, permissions: options.permissions } sessionStorage.setItem('info', JSON.stringify(store.getters.info)); // 權限切換後要根據新權限從新獲取新路由,再走一遍流程 store.dispatch('newRoutes', options.role) router.addRoutes(store.getters.addRouters) } }, actions: { getInfo ({commit}, token) { commit('getInfo', token) }, setRole ({commit}, options){// 切換角色,測試權限管理,不須要能夠刪除 commit('setRole', options) } }
// src/vuex/modules/routerData.js import {defaultRouter, addRouter} from '@/router/index' const routerData = { state: { routers: [], addRouters: [] }, mutations: { setRouters: (state, routers) => { state.addRouters = routers // 保存動態路由用來addRouter state.routers = defaultRouter.concat(routers) // 全部有權限的路由表,用來生成菜單列表 } }, actions: { newRoutes ({commit}, role) { // 經過遞歸路由表,刪除掉沒有權限的路由 function eachSelect (routers, userRole) { for (let j = 0; j < routers.length; j++) { if (routers[j].meta && routers[j].meta.role.length && routers[j].meta.role.indexOf(userRole) === -1) { // 若是沒有權限就刪除該路由,若是是父級路由沒權限,全部子菜單就更沒權限了,因此一併刪除 routers.splice(j, 1) j = j !== 0 ? j - 1 : j // 刪除掉沒有權限的路由後,下標應該中止 +1,保持不變,若是下標是 0的話刪除以後依然等於0 } if (routers[j].children && routers[j].children.length) { // 若是包含子元素就遞歸執行 eachSelect(routers[j].children, userRole) } } } // 拷貝這個數組是由於作權限測試的時候能夠從低級切回到高級角色,僅限演示,正式開發時省略這步直接使用 addRouter // 僅限演示 let newArr = [...addRouter] eachSelect(newArr, role) commit('setRouters', newArr) // 正式開發 // eachSelect(addRouter, role) // commit('setRouters', addRouter) } } } export default routerData
經過自定義指令獲取當前按鈕所需的有哪些權限,而後和當前用戶的權限對比,若是沒有權限則刪除按鈕ios
// btnPermission.js import Vue from 'vue' Vue.directive('roleBtn',{ bind:function (el,binding) { let roleArr = binding.value; // 獲取按鈕所需權限 let userRole = JSON.parse(sessionStorage.getItem('info')).role // 獲取當前用戶權限 if (roleArr && roleArr.indexOf(userRole) !== -1) { return false } else { el.parentNode.removeChild(el); } } }) export default Vue
<el-button type="primary" plain size="medium">查看</el-button> <el-button type="primary" plain size="medium" v-role-btn="['admin']">添加</el-button> <el-button type="danger" plain size="medium" v-role-btn="['superAdmin']">刪除</el-button> <el-button type="primary" plain size="medium" v-role-btn="['superAdmin','admin']">修改</el-button>