日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

淺談vue權(quán)限管理實(shí)現(xiàn)及流程

瀏覽:20日期:2023-01-25 11:33:43

一、整體思路

后端返回用戶權(quán)限,前端根據(jù)用戶權(quán)限處理得到左側(cè)菜單;所有路由在前端定義好,根據(jù)后端返回的用戶權(quán)限篩選出需要掛載的路由,然后使用 addRoutes 動態(tài)掛載路由。

二、實(shí)現(xiàn)要點(diǎn)

(1)路由定義,分為初始路由和動態(tài)路由,一般來說初始路由只有 login,其他路由都掛載在 home 路由之下需要動態(tài)掛載。(2)用戶登錄,登錄成功之后得到 token,保存在 sessionStorage,跳轉(zhuǎn)到 home,此時(shí)會進(jìn)入路由攔截根據(jù) token 獲取用戶權(quán)限列表。(3)全局路由攔截,根據(jù)當(dāng)前用戶有沒有 token 和 權(quán)限列表進(jìn)行相應(yīng)的判斷和跳轉(zhuǎn),當(dāng)沒有 token 時(shí)跳到 login,當(dāng)有 token 而沒有權(quán)限列表時(shí)去發(fā)請求獲取權(quán)限等等邏輯。(4)處理用戶權(quán)限,在 store.js 定義一個模塊 permission.js,專門用于處理用戶權(quán)限相關(guān)的邏輯,用戶權(quán)限列表、菜單列表都保存在此模塊;(5)用戶權(quán)限列表、菜單列表的處理,前端的路由要和后端返回的權(quán)限有一個唯一標(biāo)識(一般用路由名做標(biāo)識符),根據(jù)此標(biāo)識篩選出對應(yīng)的路由。(6)左側(cè)菜單,要和用戶信息、用戶管理模塊使用的菜單信息一致,統(tǒng)一使用保存在 store 中的變量。

三、具體實(shí)現(xiàn)流程

1、準(zhǔn)備工作,路由定義

/* router/indes.js *//* 初始路由 */let router = new Router({ mode: ’history’, routes: [ { path: ’/login’, name: ’login’, component: () => import(’@/views/login.vue’), }, ]});

/* router/indes.js *//* 準(zhǔn)備動態(tài)添加的路由 */export const dynamicRoutes = [ { path: ’/’, name: ’home’, component: () => import(’@/views/home.vue’), meta: { requiresAuth: true, }, children: [ // 用戶信息 {path: ’/user-info’,name: ’user-info’,component: () => import(’@/views/user-setting/user-info.vue’), }, // 修改密碼 {path: ’/user-password’,name: ’user-password’,component: () => import(’@/views/user-setting/user-password.vue’), }, ] }, { path: ’/403’, component: () => import(’@/views/error-page/403’), }, { path: ’*’, component: () => import(’@/views/error-page/404’), },];

系統(tǒng)主要頁面的路由,后續(xù)會將這些路由經(jīng)過權(quán)限篩選,添加到 home 路由的 children 里面

/* router/router.js */export default [ // 部署管理 { path: ’/deploy-manage’, name: ’deploy-manage’, component: () => import(’@/views/sys-admin/deploy-manage/deploy-manage.vue’), meta: { permitName: ’deploy-manage’, } }, // ...];

2、用戶登錄

用戶進(jìn)入登錄頁,輸入用戶名、密碼、驗(yàn)證碼,點(diǎn)擊登錄,發(fā)送登錄請求,登錄成功之后,將 token 保存在 sessionStorage,然后跳轉(zhuǎn)到首頁 /home ,進(jìn)入路由攔截的邏輯。

/* login.vue */// 發(fā)送登錄請求vm.$http.login(params, data => { sessionStorage.token = data.token; // ... // 跳轉(zhuǎn)到首頁 home。這里會觸發(fā)全局路由攔截 router.beforeEach vm.$router.push({ name: ’home’ });}, err => { console.log(err);});

3、全局路由攔截

首先從打開本地服務(wù) http://localhost:2001 開始,打開后會進(jìn)入 login 頁面,那么判斷的依據(jù)是什么?

首先是 token。沒有登錄的用戶是拿不到 token 的,而登錄后的用戶我們會將 token 存到 seesionStorage,因此,根據(jù)當(dāng)前有沒有 token 即可知道是否登錄。

/* 全局路由攔截 */router.beforeEach((to, from, next) => { // 根據(jù)有沒有token判斷是否登錄 if (!sessionStorage.token) { // 1、當(dāng)用戶打開localhost,to.matched === [],匹配的是空路由,此時(shí)需要重定向到login // 2、重定向到login之后,to.matched === [name: 'login', path: '/login'...] 就是上一步的login頁面 // to.matched.some(item => item.meta.requiresAuth) 這句的意思是 進(jìn)入的路由頁需要登錄認(rèn)證,取反就是不用登錄,直接通過 if (to.matched.length > 0 && !to.matched.some(item => item.meta.requiresAuth)) { next(); // 跳過,進(jìn)入下一個導(dǎo)航鉤子。比如:在 /login 路由頁刷新頁面會走到此邏輯 } else { next({ path: ’/login’ }); } } else { // 現(xiàn)在有token了 if (!store.state.permission.permissionList) { // 如果沒有 permissionList,發(fā)請求獲取用戶權(quán)限列表 store.dispatch(’permission/FETCH_PERMISSION’).then(() => {next({ path: to.path, query: to.query }); }); } else { // 現(xiàn)在有 permissionList 了 if (to.path !== ’/login’) {if (to.matched.length === 0) { // 如果匹配到的路由形如 https://172.24.1.117/?id=xxx&name=xxx,表明是關(guān)聯(lián)跳轉(zhuǎn)時(shí)沒有權(quán)限,跳轉(zhuǎn)到403 next({ path: ’/403’ });} else if (queryChange) { // 跳轉(zhuǎn)之前將路由中查詢字符串為空的過濾掉,如 xxx.com?page=&size= 這種 next({ name: to.name, params: to.params, query: to.query });} else if (sessionStorage.isSysLock === ’true’ && to.path !== ’/sys-lock’) { next({ path: ’/sys-lock’ });} else { next();} } else {// 1.如果用戶手動在地址欄輸入 /login,重定向到之前的路由頁// next(from.fullPath);// 2.如果用戶手動在地址欄輸入 /login,清除token并刷新頁面,就會去到登錄頁store.commit(’goToLogin’); } } }});

(1)當(dāng)用戶打開 localhost,此時(shí)還沒有 token,匹配的是空路由,我們重定向到登錄頁 next({ path: ’/login’ });(2)用戶在登錄頁刷新頁面,也會進(jìn)入路由攔截,此時(shí)匹配的是 login 路由,而 login 路由是不需要登錄驗(yàn)證的(requiresAuth 為空或者 false),所以直接跳過執(zhí)行 next();(3)用戶在登錄頁輸入了用戶名和密碼,登錄成功,保存了 token,跳轉(zhuǎn)到 /home 路由;(4)此時(shí)進(jìn)入路由攔截,已經(jīng)有 token了,但是還沒有用戶權(quán)限 permissionList,然后發(fā)請求獲取用戶權(quán)限列表,得到權(quán)限后 next({ path: to.path, query: to.query }); 繼續(xù)往下走;(5)再次進(jìn)入路由攔截,此時(shí)有 token 和 permissionList 了,就可以根據(jù)實(shí)際業(yè)務(wù)進(jìn)行跳轉(zhuǎn)了。上面的代碼是判斷當(dāng)前是不是 login 路由,如果用戶登錄后手動在地址欄輸入 /login,則清除 token 跳轉(zhuǎn)到登錄頁。其他的邏輯就跟具體業(yè)務(wù)相關(guān)了,就不細(xì)講了。

4、處理用戶權(quán)限

處理用戶權(quán)限,在 store.js 定義一個模塊 permission.js,專門用于處理用戶權(quán)限相關(guān)的邏輯,用戶權(quán)限列表、菜單列表都保存在此模塊;來看看 permission.js 主要做了什么:

/* permission.js *//* 由于權(quán)限這塊邏輯很多,所以在vuex添加了一個permission模塊來處理權(quán)限相關(guān)的邏輯和變量 */import httpRequest from ’@/assets/js/service/http’; // http請求import handleModule from ’@/assets/js/common/handle-module’; // 處理路由、側(cè)邊欄的公共函數(shù)import router, { dynamicRoutes } from ’@/router/index’; // 默認(rèn)路由配置,動態(tài)路由配置import permissionRouter from ’@/router/router’; // 需要權(quán)限的路由配置// ...export default { // ... actions: { async FETCH_PERMISSION({ commit, state }) { // 初始化路由表,注意這里必須寫,router.beforeEach 路由攔截時(shí),多次執(zhí)行 FETCH_PERMISSION commit(’setPermission’, []); // 發(fā)請求獲取后端返回的用戶權(quán)限 let data = await getUserByToken(); let userPopedoms = data.userPopedoms || []; // 保存用戶的權(quán)限模塊(去除掉用戶管理和登錄),用戶管理模塊可以使用,權(quán)限列表 let userPopeList = userPopedoms.filter(v => v.requestMapping !== ’user-manage’ && v.requestMapping !== ’login’); commit(’setUserPopedoms’, userPopeList); // 根據(jù)權(quán)限篩選出我們設(shè)置好的路由并加入到 path=’/’ 的children,就是home路由的children下 let routes = handleModule.getRouter(userPopedoms, permissionRouter); let homeContainer = dynamicRoutes.find(v => v.path === ’/’); // 使用concat的目的是讓 分配給用戶的權(quán)限處于 children 的第0項(xiàng) homeContainer.children = routes.concat(homeContainer.children); // 設(shè)置首頁重定向,重定向到用戶權(quán)限的第0項(xiàng) homeContainer.redirect = homeContainer.children[0].name; // 根據(jù)權(quán)限生成左側(cè)導(dǎo)航菜單 let sidebarMenu = handleModule.getSidebarMenu(userPopeList); commit(’setMenu’, sidebarMenu); // 初始路由 let initialRoutes = router.options.routes; // 動態(tài)添加路由。只有刷新頁面才會清空動態(tài)添加的路由信息 router.addRoutes(dynamicRoutes); // 完整的路由表 commit(’setPermission’, [...initialRoutes, ...dynamicRoutes]); } },};

(1)首先,let data = await getUserByToken(); 發(fā)請求獲取用戶權(quán)限,得到 data,data.userPopedoms 格式大致如下:

[ { 'moduleGroupId': 1001, 'moduleGroupName': '部署管理', 'requestMapping': 'deploy-manage', }, { 'moduleGroupId': 1100, 'moduleGroupName': '系統(tǒng)管理', 'requestMapping': 'sys-manage', 'moduleList': [ { 'moduleId': 1101, 'moduleName': '系統(tǒng)日志', 'requestMapping': 'system-log', 'moduleGroupId': 1100, }, { 'moduleId': 1102, 'moduleName': '系統(tǒng)告警', 'requestMapping': 'sys-alert', 'moduleGroupId': 1100, }, ], }]

(2)然后,根據(jù)我們寫好的路由數(shù)組,進(jìn)行對比,過濾得到我們要的路由。路由格式在上文“路由定義”的 router/router.js 已經(jīng)提到。還要根據(jù)用戶權(quán)限處理得到側(cè)邊欄菜單。

為此,我們需要兩個處理函數(shù),一個根據(jù)用戶權(quán)限列表和路由數(shù)組過濾得到最終路由,另一個根據(jù)用戶權(quán)限處理得到側(cè)邊欄菜單。所以另外專門創(chuàng)建了一個文件 handle-module.js 存放這兩個函數(shù)。

/* handle-module.js */const handleModule = { /** * 根據(jù)后臺返回的權(quán)限,以及配置好的所有路由,過濾出真實(shí)路由 * @param {Array} permissionList 后臺返回的用戶權(quán)限列表 * @param {Array} allRouter 前端配置好的所有動態(tài)路由的集合 * @return {Array} 過濾后的路由 */ getRouter(permissionList = [], allRouter = []) { // permissions 的格式為 ['deploy-manage', 'system-log'] let permissions = permissionList.reduce((acc, cur) => { if (cur.moduleList && cur.moduleList.length > 0) cur = cur.moduleList; return acc.concat(cur); }, []).map(v => v.requestMapping); return allRouter.filter(item => permissions.includes(item.meta.permitName)); }, /** * 根據(jù)后臺返回的權(quán)限,生成側(cè)邊欄 * @param {Array} permissionList 后臺返回的用戶權(quán)限列表 * @return {Array} sidebarMenu 生成的側(cè)邊欄數(shù)組 */ getSidebarMenu(permissionList = []) { let sidebarMenu = []; permissionList.forEach(item => { let menuItem = {name: item.requestMapping,title: item.moduleGroupName, }; menuItem.children = (item.moduleList || []).map(child => ({name: child.requestMapping,title: child.moduleName, })); sidebarMenu.push(menuItem); }); return sidebarMenu; }};export default handleModule;

(3)上面得到過濾后的路由數(shù)組后,加入到 path 為 ’/’ 的 children 下面

{ path: ’/’, name: ’home’, component: () => import(’@/views/home.vue’), meta: { requiresAuth: true, }, children: [ /* 將上面得到的路由加入到這里 */ // 用戶信息 {path: ’/user-info’,name: ’user-info’,component: () => import(’@/views/user-setting/user-info.vue’), }, ]}

(4)上面根據(jù)權(quán)限生成側(cè)邊欄菜單之后,保存在 store 待用。

(5)上面第三步將動態(tài)路由加入到 home 的 children 之后,就可以將 dynamicRoutes 加入到路由中了。router.addRoutes(dynamicRoutes);

(6)到了這里,路由就添加完了,也就是 FETCH_PERMISSION 操作完畢了,就可以在 action.then 里面調(diào)用 next({ path: to.path, query: to.query }); 進(jìn)去路由,也就是進(jìn)入 home。我們上面已經(jīng)將 home 路由重定向?yàn)椴藛蔚牡谝粋€路由信息,所以會進(jìn)入系統(tǒng)菜單的第一個頁面。

刷新頁面后,根據(jù) router.beforeEach 的判斷,有 token 但是沒有 permissionList ,會重新觸發(fā) action 去發(fā)請求獲取用戶權(quán)限,之前的邏輯會重新走一遍,所以沒有問題。

退出登錄后,需要清除 token 并刷新頁面。因?yàn)槭峭ㄟ^ addRoutes 添加路由的,而 vue-router 沒有刪除路由的 api,所以清除路由、清除 store 中存儲的各種信息,刷新頁面是最保險(xiǎn)的。

相關(guān)文件的目錄截圖:

淺談vue權(quán)限管理實(shí)現(xiàn)及流程

四、總結(jié)

缺點(diǎn):全局路由守衛(wèi)里,每次路由跳轉(zhuǎn)都要做判斷;每次刷新頁面,需要重新發(fā)請求獲取用戶權(quán)限;退出登錄時(shí),需要刷新一次頁面將動態(tài)添加的路由以及權(quán)限信息清空;

優(yōu)點(diǎn):菜單與路由分離,菜單的修改、添加、刪除由后端控制,利于后期維護(hù);使用 addRoutes 動態(tài)掛載路由,可控制用戶不能在 url 輸入相關(guān)地址進(jìn)行跳轉(zhuǎn);

vue權(quán)限管理還有其他實(shí)現(xiàn)方式,大家可以根據(jù)實(shí)際業(yè)務(wù)考慮做調(diào)整,以上的實(shí)現(xiàn)方式是比較適合我們現(xiàn)有項(xiàng)目的需求的。以上,有問題歡迎提出交流,喜歡的話點(diǎn)個贊哦~

到此這篇關(guān)于淺談vue權(quán)限管理實(shí)現(xiàn)及流程的文章就介紹到這了,更多相關(guān)vue權(quán)限管理內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Vue
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
免费在线小视频| 国产成人a视频高清在线观看| 91成人精品视频| 丝袜美腿亚洲一区二区图片| 日韩精品欧美大片| 国精品产品一区| 尹人成人综合网| 国产日韩一区二区三区在线播放| 国产精品毛片久久| 精品欧美久久| 97久久中文字幕| 日韩欧美国产精品综合嫩v| 欧美91视频| 免费人成黄页网站在线一区二区| 久久精品av麻豆的观看方式| av免费不卡国产观看| 女同性一区二区三区人了人一| 日韩一区二区三免费高清在线观看| 欧美国产精品| 日韩午夜一区| 欧美激情三区| 免费成人网www| 欧美视频久久| 久久婷婷激情| 日韩二区三区四区| 亚洲精品在线影院| 日韩一区二区三区在线看| 日韩精品永久网址| 蜜臀久久99精品久久久久宅男 | 亚欧成人精品| 欧美韩日一区| 日本强好片久久久久久aaa| 免费一二一二在线视频| 日韩不卡在线观看日韩不卡视频| 成人精品中文字幕| 国产欧美自拍一区| 国产精品社区| 国产美女高潮在线观看| 日本在线视频一区二区| 日韩欧美一区二区三区在线视频| 婷婷综合国产| 久久久夜精品| 国产日产精品_国产精品毛片| 香蕉久久精品| 老鸭窝一区二区久久精品| 蜜臀精品一区二区三区在线观看| 欧美二三四区| 国产精品一区二区三区www| 黄色成人在线网址| 福利一区和二区| 国产欧美一区二区三区精品观看| 99热精品在线观看| 欧洲av不卡| 久久国产精品美女| 亚洲永久精品唐人导航网址| 午夜av成人| 久久久91麻豆精品国产一区| 亚洲一区国产一区| 91精品一区二区三区综合| 捆绑调教美女网站视频一区| 日韩国产精品久久久久久亚洲| 9色精品在线| 日韩精品久久久久久久电影99爱| 国产极品模特精品一二| 亚洲精选av| 精品在线99| 91av亚洲| 精品一区电影| 国产麻豆一区二区三区| 亚洲日本在线观看视频| 国产农村妇女精品一二区| 久久在线视频免费观看| 国产一区二区三区不卡av| 国产调教精品| 清纯唯美亚洲综合一区| 亚洲男人在线| 麻豆91精品| 国产视频一区在线观看一区免费| 亚洲高清毛片| 久久蜜桃精品| 日韩在线视频精品| 国产欧洲在线| 日韩国产激情| 高清一区二区| 精品欠久久久中文字幕加勒比| 国产欧美日韩在线观看视频| 91精品麻豆| 日韩一二三区在线观看| 亚洲精品中文字幕99999| 蜜桃久久久久久久| 蜜桃久久av| 亚洲一二三区视频| 香蕉久久一区| 欧美日韩中文| 国产美女精品视频免费播放软件| 日韩高清电影一区| 日本欧美一区| 国产精品久久久久久久久久妞妞| 国产精品亚洲四区在线观看| 国产精品sss在线观看av| 国产精品第一国产精品| 久久99视频| 久久精品三级| 水蜜桃久久夜色精品一区| 日韩电影二区| 欧美中文字幕一区二区| 亚洲一区久久| 日本中文字幕一区二区视频| 日本欧美一区| 国内自拍视频一区二区三区| 91av亚洲| 欧美另类综合| 日韩中文av| 国产精品久久久久久久久免费高清 | 在线日韩成人| 亚洲精品激情| 欧美亚洲人成在线| 欧美a级一区二区| 高清久久一区| 免费观看久久av| 蜜桃久久精品一区二区| 欧美亚洲一区二区三区| 成人高清一区| 亚洲手机视频| 一区二区高清| 欧美国产另类| 亚洲成人精品| 亚洲一区免费| 国产一精品一av一免费爽爽| 国产成人免费精品| 天堂网在线观看国产精品| 深夜福利亚洲| 成人亚洲一区二区| 91九色精品| 国产精品综合| 久久精品影视| 亚洲久久一区| 国产一区二区三区四区五区 | 色婷婷久久久| 热久久国产精品| 国产精品一区2区3区| 色婷婷精品视频| 中文字幕日本一区二区| 精品欧美日韩精品| 欧美jjzz| 国产毛片一区二区三区 | 日韩欧美三区| 国产精品伦理久久久久久| 欧美特黄a级高清免费大片a级| 日韩高清一区二区| 精品视频网站| 免费久久99精品国产自在现线| 18国产精品| 亚洲成人不卡| 日韩国产一二三区| 成人精品中文字幕| 日韩美女国产精品| 色老板在线视频一区二区| 日韩一区二区三区在线看| 91一区二区三区四区| 免费一级片91| 日韩在线免费| 日本va欧美va精品| 久久中文字幕二区| 国产精品一区三区在线观看| 久久久一本精品| 欧美天堂一区二区| 久久要要av| 美腿丝袜亚洲一区| 日韩视频精品在线观看| 免费亚洲婷婷| 日韩精品一级二级| 日韩免费av| 国产欧美日韩免费观看| 亚洲欧美日韩高清在线| 久久精品国产免费| 日本大胆欧美人术艺术动态| 五月天av在线| 国产精品探花在线观看| 国产免费成人| 国产精品久久久久久久久久10秀| 深夜日韩欧美| 国产99精品一区| 麻豆久久一区| 午夜久久av| 亚洲免费激情| 成人久久久久| 久久精品国产亚洲一区二区三区| 蜜臀av国产精品久久久久| 肉色欧美久久久久久久免费看| 欧美日韩精品一区二区三区视频 | 亚洲欧美日本国产| 99精品在线免费在线观看| 美女性感视频久久| 综合一区在线| 亚洲中字黄色| 成人午夜国产| 国产精品久久久久久久久妇女| 欧美伊人久久| 亚洲1区在线观看|