後臺管理系統都有這種需求,不一樣角色帳號進來後,就只能看到本身權限內的頁面
這種權限限制,須要先後端共同完成。後端須要在用戶越權訪問時,返回錯誤提示。vue
也可以讓後端直接返回路由列表。只是這樣不夠靈活,以後每新增一個頁面都要他們配置路由和權限,不符合先後端分離原則。webpack
import layoutHeaderAside from '@/layout/header-aside' // 因爲懶加載頁面太多的話會形成webpack熱更新太慢,因此開發環境不使用懶加載,只有生產環境使用懶加載 const _import = process.env.NODE_ENV === 'development' ? file => require('@/views/' + file).default : file => () => import('@/views/' + file) /** * 在主框架內顯示 */ const frameIn = [ { path: '/', redirect: { name: 'index' }, component: layoutHeaderAside, children: [ // 首頁 { path: '/index', name: 'index', component: _import('system/index') }, // 刷新頁面 必須保留 { path: '/refresh', name: 'refresh', hidden: true, component: _import('system/function/refresh') }, // 頁面重定向 必須保留 { path: '/redirect/:route*', name: 'redirect', hidden: true, component: _import('system/function/redirect') } ] } ] /** * 在主框架以外顯示 */ const frameOut = [ // 登陸 { path: '/login', name: 'login', component: _import('system/login') } ] /** * 錯誤頁面 */ const errorPage = [ { path: '*', name: '404', component: _import('system/error/404') } ] // 導出須要顯示菜單的 export const frameInRoutes = frameIn // 從新組織後導出 export default [ ...frameIn, ...frameOut, ...errorPage ]
import layoutHeaderAside from '@/layout/header-aside' const _import = process.env.NODE_ENV === 'development' ? file => require('@/views/' + file).default : file => () => import('@/views/' + file) const lists = [ { path: '/', redirect: { name: 'index' }, component: layoutHeaderAside, children: [ // 機構管理 { path: '/organization-management', name: 'organizationManagement', meta: { title: '機構管理', auth: true, roles: [0] // 有權進入的角色 }, component: _import('pages/organization-management') }, // 人員管理 { path: '/personnel-management', name: 'personnelManagement', meta: { title: '人員管理', auth: true, roles: [0] }, component: _import('pages/personnel-management') }, // 角色管理 { path: '/roles-management', name: 'rolesManagement', meta: { title: '角色管理', auth: true, roles: [0] }, component: _import('pages/roles-management') }, // 角色受權 { path: '/roles-impower', name: 'rolesImpower', meta: { title: '受權', auth: true, roles: [0] }, component: _import('pages/roles-management/components/roles-impower') }, { path: 'authority-management', name: 'authority-management', meta: { title: '權限管理', auth: true, roles: [0] }, component: _import('pages/authority-management') }, { path: 'agency-register-approval', name: 'agency-register-approval', meta: { title: '機構註冊審批', auth: true, roles: [1] }, component: _import('pages/agency-register-approval') }, { path: 'program-info-management', name: 'program-info-management', meta: { title: '項目信息管理', auth: true, roles: [1] }, component: _import('pages/program-info-management') }, { path: 'product-category-management', name: 'product-category-management', meta: { title: '產品類目管理', auth: true, roles: [1] }, component: _import('pages/product-category-management') } ] } ] export default lists
// 菜單 側邊欄 export default [ { path: '/index', title: '首頁', icon: 'home', roles: [0, 1] }, { path: '/organization-management', title: '機構管理', icon: 'institution', roles: [0] }, { title: '用戶管理', icon: 'user', roles: [0], children: [ { path: '/personnel-management', title: '人員管理', icon: '', roles: [0] }, { path: '/roles-management', title: '角色管理', icon: '', roles: [0] } ] }, { title: '權限管理', icon: 'shield', roles: [0], children: [ { path: '/authority-management', title: '權限管理', icon: '', roles: [0] } ] }, { title: '註冊審批', icon: 'legal', roles: [1], children: [{ path: '/agency-register-approval', title: '機構註冊審批', icon: '', roles: [1] }] }, { title: '項目管理', icon: 'window-restore', roles: [1], children: [{ path: '/program-info-management', title: '項目信息管理', icon: '', roles: [1] }] }, { title: '類目管理', icon: 'database', roles: [1], children: [{ path: '/product-category-management', title: '產品類目管理', icon: '', roles: [1] }] } ]
import routes from './routes' // 側邊欄菜單數據 import menuAside from '@/menu/aside' /** * 路由攔截 * 權限驗證 */ router.beforeEach(async (to, from, next) => { // 進度條 NProgress.start() // 關閉搜索面板 store.commit('d2admin/search/set', false) async function getRouteAndMenu () { await store.dispatch('d2admin/user/GenerateRoutes') // 獲取可訪問路由,在 vuex 中保存 router.addRoutes(store.state.d2admin.user.accessedRouters) // 和原有的固定路由合併到一塊兒 // 獲取側邊欄菜單,在 vuex 中保存 await store.dispatch('d2admin/menu/GenerateMenu', { role: store.state.d2admin.user.info.role, menuAside }) // 設置側邊欄菜單 store.commit('d2admin/menu/asideSet', store.state.d2admin.menu.aside) next({ ...to, replace: true }) // hack 以確保路由增長後,再進行跳轉 } if (from.name === null && to.name === '404') { // 避免刷新出現 404 頁面 getRouteAndMenu() } // 在須要驗證的路由中,進一步判斷角色路由 if (to.matched.some(r => r.meta.auth)) { // 將cookie裏是否存有token做爲驗證是否登陸的條件 const token = util.cookies.get('token') if (token && token !== 'undefined') { const accessedRouters = store.state.d2admin.user.accessedRouters if (accessedRouters.length <= 0) { // 本地沒有保存可訪問路由,就須要計算 getRouteAndMenu() } else { next() } } else { // 沒有登陸的時候跳轉到登陸界面 // 攜帶上登錄成功以後須要跳轉的頁面完整路徑 next({ name: 'login', query: { redirect: to.fullPath } }) NProgress.done() } } else { // 不須要身份校驗 直接經過 next() } })
actions: { /** * @description 登陸 * @param {Object} context * @param {Object} payload username {String} 用戶帳號 * @param {Object} payload password {String} 密碼 * @param {Object} payload route {Object} 登陸成功後定向的路由對象 任何 vue-router 支持的格式 */ // 登陸後保存用戶角色信息 login ({ dispatch }, { username = '', password = '' } = {}) { return new Promise((resolve, reject) => { // 開始請求登陸接口 AccountLogin({ username, password }) .then(async res => { // 設置 cookie 必定要存 uuid 和 token 兩個 cookie // 整個系統依賴這兩個數據進行校驗和存儲 // uuid 是用戶身份惟一標識 用戶註冊的時候肯定 而且不可改變 不可重複 // token 表明用戶當前登陸狀態 建議在網絡請求中攜帶 token // 若有必要 token 須要定時更新,默認保存一天 util.cookies.set('uuid', res.userId) util.cookies.set('token', res.token) // 設置 vuex 用戶信息,保存用戶名稱和用戶角色 await dispatch('d2admin/user/set', { name: res.userName, role: res.userType }, { root: true }) // 用戶登陸後從本地儲存中加載一系列的設置 await dispatch('load') // 結束 resolve() }) .catch(err => { console.log('err: ', err) reject(err) }) }) } }
// 原始菜單列表 import authRoutes from '@/router/auth-routes' // 判斷當前路由字段的 roles 數組裏是否包含用戶角色 function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return route.meta.roles.some(role => role === roles) } else { return true } } export default { namespaced: true, state: { // 用戶信息 // 其中的 role , 0 是管理員, 1 是非管理員 info: {}, accessedRouters: [] }, mutations: { // 保存當前用戶的可訪問路由 setRouters (state, routers) { state.accessedRouters = routers } }, actions: { // 生成根據權限可訪問的路由 // 保存並返回 GenerateRoutes({ state, commit }) { return new Promise(resolve => { const { role } = state.info; const accessedRouters = authRoutes.filter(v => { if (hasPermission(role, v)) { if (v.children && v.children.length > 0) { v.children = v.children.filter(child => { if (hasPermission(role, child)) { return child } return false; }); return v } else { return v } } return false; }); commit('setRouters', accessedRouters); resolve(accessedRouters); }) } } }
與路由 module 同樣步驟
web