vue-router后臺鑒權流程實現(xiàn)
前言:
最近項目遇到一個管理系統(tǒng),感覺權限配置挺有意思,記錄一下流程實現(xiàn)的過程,便于自己學習以及整理思路,部分思路整合在代碼的注釋中:
路由攔截鑒權常用的兩種方法
路由攔截:單純給路由加字段標識符,通過路由攔截實現(xiàn)
動態(tài)路由:第二種是通過路由的拆分另外需要后端的配合去實現(xiàn)的動態(tài)路由配置
比較:
路由攔截實現(xiàn)方式比較簡單,只需要簡單的在router.beforeEach中根據路由配置信息過濾頁面是否有權限前往改組件,若相對于的權限不夠則不前往相應的組件
動態(tài)路由實現(xiàn)相對比較復雜,并且需要后端的配合,本質是路由配置表分成兩部分,相應的不同用戶登錄的時候,是根據用戶權限信息過濾篩選除路由配置表,動態(tài)添加,而用戶沒有權限的部分則不渲染,更適合相對比較大型的后臺系統(tǒng)
注:本篇內容主要介紹動態(tài)路由鑒權實現(xiàn)方式
與動態(tài)路由相關的通常有以下幾個文件:
- router.js
- permission.js(全局的路由攔截文件)
- store.js
router.js
router.js的路由配置表可以分為兩部分,公共路由以及動態(tài)權限路由,動態(tài)權限路由可以放在前端,鑒權的時候前端自己進行數(shù)組的過濾,也可以放在后端過濾,思路相同,下面介紹的是配置表都放在前端的
export default new ?Router({? routes:[ ? ?{ ?? ??? ?path:'/login', ?? ??? ?name:'login', ?? ??? ?component:aa ?? ?}, ?? ?{ ?? ??? ?path:'/home', ?? ??? ?name:'home', ?? ??? ?component:cc ?? ?}, ?? ?] })
上面這個是一般項目的路由配置,現(xiàn)在我們需要做鑒權所以需要把路由配置表稍微拆分一下,拆成以下兩個數(shù)組:
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export const defauleRoute = [ //固定部分權限的數(shù)組,所有用戶都能訪問的路由 ?? ?{ ?? ??? ?path:'/login', ?? ??? ?component:aa ?? ?}, ] export const ?asyncRoute = [ //動態(tài)配置的路由表,工作之前需要過濾 ?? ?{ ?? ??? ?path:'/order', ?? ??? ?name:'order', ?? ??? ?component:aa, ?? ??? ?meta:{ ?? ??? ??? ?system:'order' ?? ??? ?} ?? ?} ?? ?{ ?? ??? ?path:'/roles', ?? ??? ?name:'roles', ?? ??? ?component:aa, ?? ??? ?meta:{ ?? ??? ??? ?system:'roles' ?? ??? ?} ?? ?} ] //注冊路由工作表 const createRouter = () => new Router({ ?? ? ?// mode: 'history', // require service support ?? ? ?scrollBehavior: () => ({ y: 0 }), ?? ? ?routes: constantRoutes }) const router = createRouter() //重置路由工作表,退出登錄的時候需要調用此方法 export function resetRouter() { ? const newRouter = createRouter() ? router.matcher = newRouter.matcher? } export default router
permission.js
permission文件主要做全局的路由攔截,以及路由根據用戶權限動態(tài)過濾等功能,那么這部分內容主要設涉及的就是兩個問題
- 什么時候去處理動態(tài)路由
- 什么條件去處理路由
import router from './router' import store from './store' import { getToken } from '@/utils/auth' // 自定義封裝存取token的方法 Route.beforeEach((to,from,next) =>{ ?? ?//取token,判斷用戶是否已登錄 ?? ?const ?hasToken = getToken()? ?? ?if(hasToken ){ ?? ?//判斷用戶已登錄 ?? ??? ?if(to.path === "/login"){ ?? ??? ??? ?/** ?? ??? ??? ?*用戶已經登陸,但是還路由到login頁面,這代表用戶已經執(zhí)行了退出登錄的操 ?? ??? ??? ?*作,所以這個地方可以清一下token之類的,或者自定義寫一些邏輯 ?? ??? ??? ?*/ ?? ??? ??? ?next() ?? ??? ?}else{ ?? ??? ?/** ?? ??? ?*這里是已經登錄或者點擊了登錄按鈕,token已經存入localstorage,但是但是不路 ?? ??? ?*由到login的情況如果沒有路由到/login,那么就直接讓他放行就行,在這里面我處 ?? ??? ?*理一些東西,就是用戶既然已經登陸,并且可以直接放行,那么我們放 ?? ??? ?*行之前,在這個地方需要做一些邏輯,就是判斷用戶的權限,然后根 ?? ??? ?*據用戶的權限,把我們的動態(tài)配置的路由表中符合他權限的那幾條路 ?? ??? ?*由給過濾出來,然后插入到路由配置表中去使用 ?? ??? ?* ?? ??? ?*那么就涉及到兩個問題: ?? ??? ?*1:什么時候去處理動態(tài)路由(登陸之后,進入到首頁之前,也就 ?? ??? ?*是next之前) ?? ??? ?*2:什么條件處理動態(tài)路由 ?? ??? ?*/ ?? ??? ? ?? ??? ?/** ?? ??? ?*這地方可以先判斷一下store中的用戶權限列表長度是否為0,若長度為0,則代表用戶 ?? ??? ?*是剛點擊了登錄按鈕,但是還沒有進入到頁面,這時候需要再去做一些權限過濾之類的?? ? ?? ??? ?*操作如果長度不為0代表鑒權流程都沒問題了,直接前往對應的組件就行 ?? ??? ?*這一步主要是為了防止重復過濾數(shù)組,節(jié)約性能 ?? ??? ?*/ ?? ??? ??? ?if(store.getters.roles.length > 0){ ?? ??? ??? ??? ?next() ?? ??? ??? ?}else{ ?? ??? ??? ??? ?//代碼如果走到了這個地方,代表用戶是已登錄。并且鑒權流程還沒走, ?? ??? ??? ??? ?//那么在這地方就需要去走鑒權流程 ?? ??? ??? ??? ?store.dispatch('getRoles').then(res=>{ ?? ??? ??? ??? ??? ?//這個地方的res是第三步那個地方的peomise中的resolve傳 ?? ??? ??? ??? ??? ?//過來的,也就是權限信息的那個數(shù)組 ?? ??? ??? ??? ??? ?store.dispatch('createRouters',res.data) ?? ??? ??? ??? ??? ?.then(res=>{ ?? ??? ??? ??? ??? ??? ?//這里是調用store創(chuàng)造動態(tài)路由的那個函數(shù),這個地方可以把那 ?? ??? ??? ??? ??? ??? ?//個權限數(shù)組傳到這個函數(shù)內部,或者不在這里傳,這個 ?? ??? ??? ??? ??? ??? ?//函數(shù)內部直接去取自己state里面的roles的值也是一樣的 ?? ??? ??? ??? ??? ??? ?let ?addRouters = store.getters('addRouters') ?? ??? ??? ??? ??? ??? ?let ?allRouters = store.getters('allRouters') ?? ??? ??? ??? ??? ??? ?//添加動態(tài)路由部分到工作路由 ?? ??? ??? ??? ??? ??? ?router.addRoutes(accessRoutes) ?? ??? ??? ??? ??? ??? ?//vue/cli4及之后的版本,addRoutes被廢棄,取而代之的是 ?? ??? ??? ??? ??? ??? ?//addRoute('paramentsName',route對象)或者?? ??? ??? ? ?? ??? ??? ??? ??? ??? ?//addRoute(route對象),注意,傳進去的參數(shù)不再是一個數(shù)組, ?? ??? ??? ??? ??? ??? ?//而是每一條路由對象,如果套添加多條,那么就需要遍歷添加 ?? ??? ??? ??? ??? ??? ?//如果是傳兩個參數(shù)的寫法,那么第一個參數(shù)是父路由的名字 ?? ??? ??? ??? ??? ??? ?//這樣就是把這條路由加入到父路由的children里面去?? ??? ? ?? ??? ??? ??? ??? ??? ?//前往攔截的頁面 ? ? ? ? ? ?? ??? ??? ??? ?next({ ...to, replace: true }) ? ? ? ? ? ?? ??? ??? ??? ?//addRoute添加完路由之后一定要通過這種方式做路由跳轉, ? ? ? ? ? ?? ??? ??? ??? ?//不然可能會導致addRoute之后的第一次跳到addRoutes添加的頁 ? ? ? ? ? ?? ??? ??? ??? ?//面的時候,可能是空白頁面 ? ? ? ? ? ?? ??? ??? ??? ? ? ? ? ? ? ?? ??? ??? ??? ?//{...to}:作用:把整個路由對象傳過去做路由跳轉,包括帶上 ? ? ? ? ? ?? ??? ??? ??? ?//components那些,這樣就能保證第一次就能渲染到這個頁面 ? ? ? ? ? ?? ??? ??? ??? ?//replace:true:本次路由記錄不被瀏覽器所記錄 ?? ??? ??? ??? ??? ?})?? ? ?? ??? ??? ??? ?}) ?? ??? ??? ?} ?? ??? ?} ?? ?} else { ?? ??? ?/**這里是處理沒有token的情況,也就是說這時候用戶還沒有登陸,那 ?? ??? ?*如果沒用戶登錄,那么判斷用戶是不是去登錄頁面,如果是登錄 ?? ??? ?*頁面,就直接放行,如果沒登陸就想去訪問主頁那種頁面,就讓 ?? ??? ?*他重定向到登錄頁面 ?? ??? ?*/ ?? ??? ?if(to.path == '/login'){ ?? ??? ??? ?//這地方可以判斷的仔細一點,不一定是去login的時候再讓他直接放行,而是 ?? ??? ??? ?//前往所有公共組件的時候,都直接讓他放行 ?? ??? ??? ?next() ?? ??? ?}else{ ?? ??? ??? ?next('/login') ?? ??? ?} ?? ?} })
addRoutes動態(tài)添加路由兩個注意點:
addRoutes:
Vue/cli4及之后的版本,addRoutes被廢棄,取而代之是addRoute('parentName',Route)或者addRoute(route對象),如果是傳兩個參數(shù)的寫法,那么第一個參數(shù)是父路由的name這樣就是把這條路由加入到父路由的children里面去,如果是要動態(tài)添加多天路由,就需要通過遍歷的方式了next({ ...to, replace: true }):
addRoute首次添加完路由之后的路由跳轉一定要通過這種方式做路由跳轉,不然可能會導致addRoute之后的第一次跳到addRoutes添加的頁面的時候,可能是空白頁面
{...to}:作用:把整個路由對象傳過去做路由跳轉,包括帶上components那些,這樣就能保證第一次前往addRoutes動態(tài)添加的就能渲染到這個頁面
replace:true:本次路由記錄不被瀏覽器所記錄
store.js
//在api文件夾中定義一個獲取此用戶的權限的接口,并且在這個actions中調用 import { getUserRole } from "../api/getRoles" ?//獲取權限的接口 import { logout } from '../api/user' ? //用戶退出登錄的接口 import { resetRouter } from './router' import { removeToken } from '@/utils/auth' // 自定義封裝清除token的方法 //這個是過濾數(shù)組的方法,如果路由表是多層嵌套的,那么可以遞歸調用這個方法去過濾數(shù)組 //function hasPermission(roles, route) { // ?if (route.meta && route.meta.roles) { // ? ?return roles.some(role => route.meta.roles.includes(role)) // ?} else { // ? ?return true // ?} //} //export function filterAsyncRoutes(routes, roles) { // ?const res = [] // ?routes.forEach(route => { // ? ?const tmp = { ...route } // ? ?if (hasPermission(roles, tmp)) { // ? ? ?if (tmp.children) { // ? ? ? ?tmp.children = filterAsyncRoutes(tmp.children, roles) // ? ? ?} // ? ? ?res.push(tmp) // ? ?} // ?}) // // ?return res //} //引入默認路由以及動態(tài)路由 import ?{ defauleRoute , asyncRouter } ?from '@/router' const state = { ?? ?roles:[] ? ?//掉接口拿到的權限列表,假設數(shù)據格式為:["order","roles"], ?? ?allRouters: [], //這個是全部整合以后,最終要工作的路由 ?? ?addRouters: [],//這個是根據權限動態(tài)匹配過濾出來部分的路由 } ?? ? ? const getters = { ?? ?/**把state中的roles存入到這個getters中,那么其他獲取這個getters中的 ?? ?*roles的地方,只要原本的roles發(fā)生改變,其他地方的這個roles也就會發(fā)生 ?? ?*改變了,這個相當于是computed計算屬性 ?? ?*/ ?? ?roles:state => state.roles ?? ?allRouters:state => state.allRouters ?? ?addRouters:state => state.addRouters } const mutations:{ ?? ?/**在下面的actions里面通過commit把權限信息的數(shù)組提交到這個地方,然后 ?? ?*這個地方把數(shù)組提交到state的roles ?? ?*/ ?? ?SetRoute(state,router) ?? ??? ?//這個地方的router就是根據用戶權限,過濾出來的路由表 ?? ??? ?state.allRouters = defauleRoute.concat(router) ?? ??? ?state.addRouters = router ?? ?} ?? ?//把路由權限數(shù)組存儲到state ?? ?setRoles(state,value){ ?? ??? ?state.roles = value ?? ?} } const actions:{ ?? ?//寫一個獲取當前登陸角色權限的請求,比如["/order","roles"],如果請求回 ?? ?//來的是這樣的,那么就代表這個角色的權限就是可以訪問 order路由以及 ?? ?//roles路由 ?? ? ?? ?//獲取權限信息可能有兩種情況:除了下面這種權限信息是一個單獨的接口, ?? ?//權限信息也可能跟著用戶登陸的接口就一并返回 ?? ?//獲取當前用戶的權限信息,并且存入到state中,這個權限信息,可能跟后 ?? ?//端在溝通的時候,他不會單獨寫成一個接口給你去請求,而是你在登陸請求 ?? ?//的時候就把用戶信息和這個此用戶的權限信息都一次性返回給你了,那就在 ?? ?//用戶登陸的時候就把這個權限信息存入到這個state中,也一 ?? ?//樣的,目的就是要把權限信息的數(shù)組存入到state中就行 ?? ?//獲取roles權限方法 ?? ?getRoles({commit},data){ ?? ??? ?return new Promise(resolve,reject){ ?? ??? ??? ?//調用獲取用戶權限接口 ?? ??? ??? ?getUserRole().then(res =>{ ?? ??? ??? ??? ?//這里返回的數(shù)據應該是一個權限信息的數(shù)組,如:["order","roles"] ?? ??? ??? ??? ?//把權限信息通過mutations存入到state ?? ??? ??? ??? ?commit('setRoles',res.data) ?? ??? ??? ??? ?resolve(res.data) ?? ??? ??? ?}) ?? ??? ?} ?? ?}) ?? ?//根據權限過濾數(shù)組配置表的方法 ?? ?createRouters({ commit } , data ){ ?? ??? ?return new Promise((resolve,reject) =>{ ?? ??? ??? ?let addRouters = ?[ ]? ?? ??? ??? ?if(data.includes("admin"){ ?? ??? ??? ??? ?addRouters = asyncRouter ?? ??? ??? ?}else{ ?? ??? ??? ??? ?//項目開發(fā)中路由數(shù)組可能是多層嵌套,那么這地方需要用上面自定義的方?? ? ?? ??? ??? ??? ?//法通過遞歸的方式去過濾,此demo就只按一層數(shù)組處理 ?? ??? ??? ??? ?//(filterAsyncRoutes)方法 ?? ??? ??? ??? ?addRouters = asyncRouter.filter(item=>{ ?? ??? ??? ??? ??? ?if(data.includes(item.meta.system) ){ ?? ??? ??? ??? ??? ? ? ?? ?return item ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?}) ?? ??? ??? ?} ?? ??? ??? ? ?? ??? ??? ? ?? ??? ??? ?//把這個匹配出來的權限路由傳到mutations中,讓mutations ?? ??? ??? ?//把這個匹配出來的路由存入到state ?? ??? ??? ?commit.("SetRoute",addRouters) ?? ??? ??? ?resolve() ?//這個地方要調用一下這個resolve,這樣外面訪可以通過 ?? ??? ??? ??? ??? ? ? //.then拿到數(shù)組過濾成功的回調 ?? ??? ?}) ?? ?}, ?? ?logout({ commit }) { ?? ? ? ?return new Promise((resolve, reject) => { ?? ? ? ? ?logout().then(() => { ?? ? ? ? ? ?removeToken() // must remove ?token ?first ?? ? ? ? ? ?resetRouter() ?? ? ? ? ? ?commit('setRoles', []) ?? ? ? ? ? ?commit('SetRoute', []) ?? ? ? ? ? ?resolve() ?? ? ? ? ?}).catch(error => { ?? ? ? ? ? ?reject(error) ?? ? ? ? ?}) ?? ? ? ?}) ? }, } export default { ?? ?state, ?? ?getters, ?? ?mutations, ?? ?actions }
退出登錄:
async function logout(){ try{ const res = await store.dispatch.logout() if(res.code == 200){ //退出登錄成功 } }catch{ //退出登錄失?。ǔ鲥e了) } }
結尾:
代碼一大堆,其實思路很簡單,不過是拿到路由配置表,過濾數(shù)組,動態(tài)添加而已
項目參考github:vue-element-admin
到此這篇關于vue-router后臺鑒權流程實現(xiàn)的文章就介紹到這了,更多相關vue-router后臺鑒權 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue 路由緩存 路由嵌套 路由守衛(wèi) 監(jiān)聽物理返回操作
這篇文章主要介紹了vue 路由緩存 路由嵌套 路由守衛(wèi) 監(jiān)聽物理返回操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Vue實現(xiàn)boradcast和dispatch的示例
這篇文章主要介紹了Vue實現(xiàn)boradcast和dispatch的示例,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下2020-11-11vue element 生成無線級左側菜單的實現(xiàn)代碼
這篇文章主要介紹了vue element 生成無線級左側菜單的實現(xiàn)代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08如何為vuex實現(xiàn)帶參數(shù)的 getter和state.commit
這篇文章主要介紹了如何為vuex實現(xiàn)帶參數(shù)的getter和state.commit,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01vue使用recorder-core.js實現(xiàn)錄音功能
這篇文章主要介紹了vue如何使用recorder-core.js實現(xiàn)錄音功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07