Vue路由權限控制解析
前言
本人在公司主要負責中后臺系統(tǒng)的開發(fā),其中路由和權限校驗算是非常重要且最為基本的一環(huán)。實際開發(fā)項目中,關于登錄和路由權限的控制參照了vue-element-admin這個明星項目,并在此基礎上基于業(yè)務進行了整合,接下來我會以這個項目為例,仔細地剖析整個路由和權限校驗的過程,也算是對這個知識點的一些總結。
項目總體目錄結構
進入今天主題之前,我們先來梳理下整個項目,src目錄下的。
- api: 接口請求
- assets: 靜態(tài)資源
- components: 通用組件
- directive: 自定義指令
- filters: 自定義過濾器
- icons: 圖標
- layout: 布局組件(頁面架構核心)
- router: 路由配置(路由權限核心模塊)
- store: 狀態(tài)管理
- styles: 樣式文件
- utils: 工具方法
- views: 頁面組件
- permission.js 權限管理
對這項目感興趣的同學可以自行,有針對性地學習,除了路由權限校驗的功能以外,也包含了很多有意思的功能,相信能夠學到不少東西。
路由權限控制邏輯
路由處理流程圖
路由處理源碼分析
我們先找到permission.js文件,此處定義全局路由守衛(wèi),也是路由權限中非常關鍵的核心代碼。為方便大家閱讀,只摘取了跟路由相關的代碼
import router from './router' import store from './store' import { Message } from 'element-ui' import NProgress from 'nprogress' // progress bar import 'nprogress/nprogress.css' // progress bar style import { getToken } from '@/utils/auth' // get token from cookie NProgress.configure({ showSpinner: false }) // NProgress Configuration const whiteList = ['/login', '/auth-redirect'] // 白名單配置 router.beforeEach(async(to, from, next) => { // start progress bar NProgress.start() // 有token if (hasToken) { if (to.path === '/login') // 如果當前路徑為/login,重定向到首頁 next({ path: '/' }) NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939 } else { // determine whether the user has obtained his permission roles through getInfo const hasRoles = store.getters.roles && store.getters.roles.length > 0 if (hasRoles) { next() } else { try { // 獲取用戶信息 const { roles } = await store.dispatch('user/getInfo') // 根據(jù)用戶的角色,動態(tài)生成路由 const accessRoutes = await store.dispatch('permission/generateRoutes', roles) // 動態(tài)添加路由 (將基本的路由信息跟動態(tài)路由進行合并) router.addRoutes(accessRoutes) // 繼續(xù)訪問 next({ ...to, replace: true }) } catch (error) { // 刪除token await store.dispatch('user/resetToken') Message.error(error || 'Has Error') // 重定向到登錄頁面 next(`/login?redirect=${to.path}`) NProgress.done() } } } } else { // 沒有token if (whiteList.indexOf(to.path) !== -1) { // 如果在白名單中,則不需要進行任何校驗,直接放行 next() } else { // 如果不存在于白名單中,則重定向到登錄頁面. next(`/login?redirect=${to.path}`) NProgress.done() } } }) router.afterEach(() => { // finish progress bar NProgress.done() })
注意到,代碼中的/login?redirect=${jto.path}, 這里的redirect參數(shù)主要是用于,在用戶登錄成功后進行跳轉的頁面路徑。具體功能在/views/login/index.vue文件下
watch: { $route: { handler: function(route) { const query = route.query if (query) { //路由查詢參數(shù) this.redirect = query.redirect this.otherQuery = this.getOtherQuery(query) } }, immediate: true } }, // methods下的: handleLogin() { // 登錄函數(shù) this.$refs.loginForm.validate(valid => { if (valid) { // 賬號密碼校驗成功后 this.$store.dispatch('user/login', this.loginForm) .then(() => { // 直接跳轉到this.redirect 路徑的頁面 this.$router.push({ path: this.redirect || '/', query: this.otherQuery }) this.loading = false }) } else { // .. } }) },
動態(tài)路由配置
我們先來看看路由的定義,在/src/router/index.js文件下
export const constantRoutes = [ // 用來定義普通的路由配置,不需要訪問權限的 // 路由配置對象 ] export const asyncRoutes = [ // 通過路由元信息meta.roles來設置訪問權限,一般來說是個數(shù)組 { path: '/permission', component: Layout, redirect: '/permission/page', alwaysShow: true, // will always show the root menu name: 'Permission', meta: { title: 'Permission', icon: 'lock', roles: ['admin', 'editor'] // 通過roles設置路由的權限 }, // ... } ]
動態(tài)添加路由時,本質上就是根據(jù)用戶的角色信息在asyncRoutes路由配置數(shù)組中進行路由篩選,找到相對應的路由,與constantRoutes合并生成最新的路由。
動態(tài)添加路由邏輯圖
動態(tài)路由源碼分析
代碼入口: permission.js
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
permission/generateRoutes方法入口文件:/strore/modules/permissions.js
import { asyncRoutes, constantRoutes } from '@/router' const state = { routes: [], addRoutes: [] } const mutations = { SET_ROUTES: (state, routes) => { state.addRoutes = routes state.routes = constantRoutes.concat(routes) } } const actions = { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes if (roles.includes('admin')) { // 如果包含了admin,則說明是admin,具有所有模塊的訪問權限 accessedRoutes = asyncRoutes || [] } else { // 如果不是管理員,則需要根據(jù)用戶角色roles和異步路由進行篩選 accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) } // 將最終的結果存放到vuex中 commit('SET_ROUTES', accessedRoutes) // resolve出去 resolve(accessedRoutes) }) } }
對異步路由進行篩選,并將最終的結果存放到vuex中,并將結果resolve出去
export function hasPermission(roles, route) { if (route.meta && route.meta.roles) { // 如果存在meta.roles // 只要meta.roles中存在與用戶角色列表中相同的值,則說明具有訪問權限 return roles.some(role => route.meta.roles.includes(role)) } else { // 不存在meta或者是不存在meta.roles,則說明是通用模塊,直接放行 return true } } export function filterAsyncRoutes(routes, roles) { const res = [] routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { // 相對路由數(shù)組的每一項進行訪問權限的判斷 if (tmp.children) { // 如果存在children,則遞歸調用篩選函數(shù) tmp.children = filterAsyncRoutes(tmp.children, roles) } // 將處理好的路由配置放入到res中 res.push(tmp) } }) return res }
最后回到/permission.js文件中
const accessRoutes = await store.dispatch('permission/generateRoutes', roles) // 這里的accessRoutes就是篩選之后的路由, // 最后通過route.addRoutes將constRoutes和accessRoutes進行合并,生成最終的訪問路由 router.addRoutes(accessRoutes)
擴展-按鈕權限
路由權限控制基本流程已經分析完,接下來我們也來看看項目里的按鈕權限控制的實現(xiàn),實現(xiàn)也比較簡單。
基本用法 <div v-permission="['admin','editor']"></div> import store from '@/store' function checkPermission(el, binding) { const { value } = binding // 從store中拿到我們訪問接口后,取到用戶角色信息 const roles = store.getters && store.getters.roles if (value && value instanceof Array) { // 判斷傳入的值是不是數(shù)組,規(guī)范化傳值 if (value.length > 0) { const permissionRoles = value // 只要傳入的permissionRoles中,包含了roles其中的一個值即可,則代表有權限 const hasPermission = roles.some(role => { return permissionRoles.includes(role) }) // 沒有權限則進行刪除,不展示。 // v-permission具體實現(xiàn)可以根據(jù)業(yè)務場景進行修改 if (!hasPermission) { el.parentNode && el.parentNode.removeChild(el) } } } else { throw new Error(`need roles! Like v-permission="['admin','editor']"`) } } export default { inserted(el, binding) { checkPermission(el, binding) }, update(el, binding) { checkPermission(el, binding) } }
總結
存在token
存在用戶角色信息,則說明該用戶的最終可訪問的路由已經生成,可以直接放行
不存在用戶信息
1.調用獲取用戶信息接口,獲取到用戶信息, 將用戶信息存放到vuex中
2.判斷用戶角色
- 如果是管理員則對所有模塊具有訪問權限
- 非管理員,需要對異步路由進行篩選,通過遍歷異步路由,并通過meta.roles與用戶信息比較,判斷用戶是否具有訪問權限
3.將最終的可訪問路由存放到vuex中,最后通過router.addRoutes,整合最后的路由配置列表
不存在token
如果訪問路由在白名單下,則直接進行訪問
訪問路由不存在白名單下,則重定向到登錄頁面 path: /login?redirect=/xxx,登錄成功后則跳轉到/xxx對應的頁面
以上就是Vue路由權限控制解析的詳細內容,更多關于Vue路由權限控制的資料請關注腳本之家其它相關文章!
相關文章
vuejs實現(xiàn)標簽選項卡動態(tài)更改css樣式的方法
這篇文章主要介紹了vuejs實現(xiàn)標簽選項卡-動態(tài)更改css樣式的方法,代碼分為html和js兩部分,需要的朋友可以參考下2018-05-05element-ui和vue表單(對話框)驗證提示語(殘留)清除操作
這篇文章主要介紹了element-ui和vue表單(對話框)驗證提示語(殘留)清除操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09vue3中unplugin-auto-import自動引入示例代碼
unplugin-auto-import 這個插件是為了解決在開發(fā)中的導入問題,下面這篇文章主要給大家介紹了關于vue3中unplugin-auto-import自動引入的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-02-02Vue2.0+Vux搭建一個完整的移動webApp項目的示例
這篇文章主要介紹了Vue2.0+Vux搭建一個完整的移動webApp項目的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03