vue 許可權管理
今天來說說許可權管理,因為網上已經有很多關於這方面的很多內容,博主也是借鑑了網上的一些邏輯來寫的,主要也是說說前端實現許可權管理的一個思路,也是作為自己日後面對這樣的問題的一個解決方案。 首先需要了解的就是純前端是無法實現許可權管理的,vue的許可權管理主要是基於路由實現的,當然這樣的許可權管理完全可以被繞過去的,而之所以在前端這麼做,更多是為了使用者體驗,節省不必要的載入開銷等等。 用vue來實現許可權管理,主要就是基於這個新的vue的api,addRoutes的方法來實現的,當然許可權管理也分為幾個方面,博主今天主要就是說的頁面級的許可權,思路就是利用剛剛說的api來動態載入路由,我們將路由分為兩個部分,一個是公共部分,即所有人都能看到的路由,另外一部分則是動態載入部分,這裡也簡單的將程式碼貼出來,大家參考一下就可以,網上的程式碼也是有很多
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export const constRouterMap = [ { path: '/login', name: 'Login', meta: { title: '登入', keepAlive: false }, component: () => import('@/views/Login.vue') }, { path: '/layout', component: () => import('@/views/Layout.vue'), // redirect: '/login', // redirect: '/index', children: [ { path: '/index', name: 'index', meta: { title: '首頁', keepAlive: false }, component: () => import('@/views/HomePage.vue') }, { path: '/about', name: 'about', meta: { title: '開發備忘', keepAlive: false }, component: () => import('@/views/About.vue') }, { path: '/author', name: 'author', meta: { title: '關於作者', keepAlive: false }, component: () => import('@/views/AboutAuthor.vue') }, { path: '/weather', name: 'wether-fore', meta: { title: '天氣預報', keepAlive: true }, component: () => import('@/views/WeatherFore.vue') }, { path: '/dynamic', name: 'dynamic-table', meta: { title: '動態表格', keepAlive: false }, component: () => import('@/views/DynamicTable.vue') }, { path: '/editable', name: 'editable', meta: { title: '可編輯表格', keepAlive: true }, component: () => import('@/views/TableGrid.vue') } ] } ] export const asyncRouterMap = [ { path: '/layout', component: () => import('@/views/Layout.vue'), children: [ { path: '/access', name: 'access', component: () => import('@/views/AccessTest.vue'), meta: { title: '許可權控制', roles: ['admin'], keepAlive: false } }, { path: '/cube', name: 'cube', component: () => import('@/views/MagicCube.vue'), meta: { title: '魔幻立方', roles: ['admin'], keepAlive: false } } ] }, { path: '/error', component: () => import('@/views/NotFound.vue') }, { path: '*', redirect: '/error', hidden: true } ] export default new Router({ mode: 'history', routes: constRouterMap })
看到這個程式碼應該知道,我們首先是先載入公共路由部分,然後再根據vue-router提供的路由導航鉤子,當路由進行跳轉的時候,向伺服器請求使用者的角色許可權
import router from './router' import store from '@/store/index' import { Message } from 'element-ui' const whiteList = ['/login'] router.beforeEach((to, from, next) => { if (sessionStorage.getItem('token')) { if (to.path === '/') { next('/index') } else { if (store.getters.roles.length === 0) { const roles = sessionStorage.getItem('roles') store.dispatch('permission/generateRoute', { roles }) .then(() => { console.log(store.getters.addRoutes[0].children.length) router.addRoutes(store.getters.addRoutes) next({ ...to, replace: true }) }) .catch(err => { Message.error({ message: err }) }) } else { next() } } } else { if (whiteList.indexOf(to.path) !== -1) { next() } else { next('/login') } } })
這裡後臺博主用了thinkjs的框架,博主現在還在整理,後續整理好,也會上傳到github上面。在這個導航鉤子上,我們利用了vuex來儲存角色資訊,每次登陸會進行判斷,如果沒有角色資訊,就會去觸發action來請求伺服器,伺服器返回角色欄位後,我們將他存在store裡面。另外根據上面的路由,我們將頁面許可權需要的角色放在路由的meta欄位中,所以當我們拿到角色資訊後,會和動態路由中的meta進行一一對比,需要注意的是,當路由有巢狀的children屬性時,我們還需要將children裡面的路由拿出來一一進行遞迴對比,這樣如果伺服器的角色資訊,符合路由需要的許可權,我們就將這個路由記錄下來,最後組成需要新增的路由,利用addRoutes來形成最終的路由。
generateRoute ({ commit }, data) {
return new Promise((resolve, reject) => {
const roles = []
roles.push(data.roles)
let accessRouters
console.log(roles.indexOf('admin') >= 0)
if (roles.indexOf('admin') >= 0) {
accessRouters = asyncRouterMap
} else {
accessRouters = filterAsyncRouter(asyncRouterMap, roles)
}
// console.log(accessRouters)
commit('SET_ROUTERS', accessRouters)
commit('SET_ROLES', roles)
resolve()
})
},
function hasPermission (roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.indexOf(role) >= 0)
} else {
return true
}
}
function filterAsyncRouter (asyncRouter, roles) {
const accessRouters = asyncRouter.filter(route => {
if (hasPermission(roles, route)) {
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, roles)
}
return true
}
return false
})
// console.log(accessRouters)
return accessRouters
}
結合前面的導航鉤子就形成了最終的路由,當用戶試圖訪問不存在的路由的時候,則會返回404頁面,另外也簡單的說下按鈕及頁面中檢視顯示的許可權,其實也是利用了vue的自定義指令,我們給自定義指令傳入需要的角色許可權陣列,然後和儲存在store中的許可權作對比,如果沒有許可權,則移除當前的DOM元素
import store from '@/store/index'
const permission = {
inserted (el, binding, vnode) {
const { value } = binding
const roles = store.getters && store.getters.roles
if (value && value instanceof Array && value.length > 0) {
const permissionRoles = value
const hasPermission = roles.some(role => {
return permissionRoles.includes(role)
})
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error('roles is must be Array!')
}
}
}
export default permission
這些程式碼都是博主自己寫的專案中的片段,完整的程式碼,大家有興趣可以去GitHub上面檢視。之前寫的許可權沒有問題,但是重新整理的時候,突然發現許可權需要重新整理的時候才會生效,技術有限,所以要是有同學發現程式碼有什麼問題,可以隨時告訴博主,當然博主也是會繼續踩坑下去,解決這個問題。