电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

淺談vue權限管理實現及流程

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

一、整體思路

后端返回用戶權限,前端根據用戶權限處理得到左側菜單;所有路由在前端定義好,根據后端返回的用戶權限篩選出需要掛載的路由,然后使用 addRoutes 動態掛載路由。

二、實現要點

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

三、具體實現流程

1、準備工作,路由定義

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

/* router/indes.js *//* 準備動態添加的路由 */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’), },];

系統主要頁面的路由,后續會將這些路由經過權限篩選,添加到 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、用戶登錄

用戶進入登錄頁,輸入用戶名、密碼、驗證碼,點擊登錄,發送登錄請求,登錄成功之后,將 token 保存在 sessionStorage,然后跳轉到首頁 /home ,進入路由攔截的邏輯。

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

3、全局路由攔截

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

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

/* 全局路由攔截 */router.beforeEach((to, from, next) => { // 根據有沒有token判斷是否登錄 if (!sessionStorage.token) { // 1、當用戶打開localhost,to.matched === [],匹配的是空路由,此時需要重定向到login // 2、重定向到login之后,to.matched === [name: 'login', path: '/login'...] 就是上一步的login頁面 // to.matched.some(item => item.meta.requiresAuth) 這句的意思是 進入的路由頁需要登錄認證,取反就是不用登錄,直接通過 if (to.matched.length > 0 && !to.matched.some(item => item.meta.requiresAuth)) { next(); // 跳過,進入下一個導航鉤子。比如:在 /login 路由頁刷新頁面會走到此邏輯 } else { next({ path: ’/login’ }); } } else { // 現在有token了 if (!store.state.permission.permissionList) { // 如果沒有 permissionList,發請求獲取用戶權限列表 store.dispatch(’permission/FETCH_PERMISSION’).then(() => {next({ path: to.path, query: to.query }); }); } else { // 現在有 permissionList 了 if (to.path !== ’/login’) {if (to.matched.length === 0) { // 如果匹配到的路由形如 https://172.24.1.117/?id=xxx&name=xxx,表明是關聯跳轉時沒有權限,跳轉到403 next({ path: ’/403’ });} else if (queryChange) { // 跳轉之前將路由中查詢字符串為空的過濾掉,如 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)當用戶打開 localhost,此時還沒有 token,匹配的是空路由,我們重定向到登錄頁 next({ path: ’/login’ });(2)用戶在登錄頁刷新頁面,也會進入路由攔截,此時匹配的是 login 路由,而 login 路由是不需要登錄驗證的(requiresAuth 為空或者 false),所以直接跳過執行 next();(3)用戶在登錄頁輸入了用戶名和密碼,登錄成功,保存了 token,跳轉到 /home 路由;(4)此時進入路由攔截,已經有 token了,但是還沒有用戶權限 permissionList,然后發請求獲取用戶權限列表,得到權限后 next({ path: to.path, query: to.query }); 繼續往下走;(5)再次進入路由攔截,此時有 token 和 permissionList 了,就可以根據實際業務進行跳轉了。上面的代碼是判斷當前是不是 login 路由,如果用戶登錄后手動在地址欄輸入 /login,則清除 token 跳轉到登錄頁。其他的邏輯就跟具體業務相關了,就不細講了。

4、處理用戶權限

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

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

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

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

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

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

/* handle-module.js */const handleModule = { /** * 根據后臺返回的權限,以及配置好的所有路由,過濾出真實路由 * @param {Array} permissionList 后臺返回的用戶權限列表 * @param {Array} allRouter 前端配置好的所有動態路由的集合 * @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)); }, /** * 根據后臺返回的權限,生成側邊欄 * @param {Array} permissionList 后臺返回的用戶權限列表 * @return {Array} sidebarMenu 生成的側邊欄數組 */ 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)上面得到過濾后的路由數組后,加入到 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)上面根據權限生成側邊欄菜單之后,保存在 store 待用。

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

(6)到了這里,路由就添加完了,也就是 FETCH_PERMISSION 操作完畢了,就可以在 action.then 里面調用 next({ path: to.path, query: to.query }); 進去路由,也就是進入 home。我們上面已經將 home 路由重定向為菜單的第一個路由信息,所以會進入系統菜單的第一個頁面。

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

退出登錄后,需要清除 token 并刷新頁面。因為是通過 addRoutes 添加路由的,而 vue-router 沒有刪除路由的 api,所以清除路由、清除 store 中存儲的各種信息,刷新頁面是最保險的。

相關文件的目錄截圖:

淺談vue權限管理實現及流程

四、總結

缺點:全局路由守衛里,每次路由跳轉都要做判斷;每次刷新頁面,需要重新發請求獲取用戶權限;退出登錄時,需要刷新一次頁面將動態添加的路由以及權限信息清空;

優點:菜單與路由分離,菜單的修改、添加、刪除由后端控制,利于后期維護;使用 addRoutes 動態掛載路由,可控制用戶不能在 url 輸入相關地址進行跳轉;

vue權限管理還有其他實現方式,大家可以根據實際業務考慮做調整,以上的實現方式是比較適合我們現有項目的需求的。以上,有問題歡迎提出交流,喜歡的話點個贊哦~

到此這篇關于淺談vue權限管理實現及流程的文章就介紹到這了,更多相關vue權限管理內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Vue
相關文章:
主站蜘蛛池模板: ◆大型吹塑加工|吹塑加工|吹塑代加工|吹塑加工厂|吹塑设备|滚塑加工|滚塑代加工-莱力奇塑业有限公司 | 小型气象站_车载气象站_便携气象站-山东风途物联网 | 螺杆真空泵_耐腐蚀螺杆真空泵_水环真空泵_真空机组_烟台真空泵-烟台斯凯威真空 | 石家庄网站建设|石家庄网站制作|石家庄小程序开发|石家庄微信开发|网站建设公司|网站制作公司|微信小程序开发|手机APP开发|软件开发 | 石栏杆_青石栏杆_汉白玉栏杆_花岗岩栏杆 - 【石雕之乡】点石石雕石材厂 | 连续密炼机_双转子连续密炼机_连续式密炼机-南京永睿机械制造有限公司 | MOOG伺服阀维修,ATOS比例流量阀维修,伺服阀维修-上海纽顿液压设备有限公司 | 存包柜厂家_电子存包柜_超市存包柜_超市电子存包柜_自动存包柜-洛阳中星 | 河南新乡德诚生产厂家主营震动筛,振动筛设备,筛机,塑料震动筛选机 | 密集架-密集柜厂家-智能档案密集架-自动选层柜订做-河北风顺金属制品有限公司 | 首页|成都尚玖保洁_家政保洁_开荒保洁_成都保洁 | 旗帜网络笔记-免费领取《旗帜网络笔记》电子书 | 阻燃剂-氢氧化镁-氢氧化铝-沥青阻燃剂-合肥皖燃新材料 | 阀门智能定位器_电液动执行器_气动执行机构-赫尔法流体技术(北京)有限公司 | 一体化污水处理设备-一体化净水设备-「山东梦之洁水处理」 | 喷漆房_废气处理设备-湖北天地鑫环保设备有限公司 | 楼承板设备-楼承板成型机-免浇筑楼承板机器厂家-捡来 | 冷热冲击试验箱_温度冲击试验箱价格_冷热冲击箱排名_林频厂家 | 蓝牙音频分析仪-多功能-四通道-八通道音频分析仪-东莞市奥普新音频技术有限公司 | 恒温恒湿试验箱厂家-高低温试验箱维修价格_东莞环仪仪器_东莞环仪仪器 | 保镖公司-私人保镖-深圳保镖公司【环宇兄弟保镖】 | 工作心得_读书心得_学习心得_找心得体会范文就上学道文库 | 厚壁钢管-厚壁无缝钢管-小口径厚壁钢管-大口径厚壁钢管 - 聊城宽达钢管有限公司 | 意大利Frascold/富士豪压缩机_富士豪半封闭压缩机_富士豪活塞压缩机_富士豪螺杆压缩机 | 雨燕360体育免费直播_雨燕360免费NBA直播_NBA篮球高清直播无插件-雨燕360体育直播 | 鑫达滑石-辽宁鑫达滑石集团| 密封无忧网 _ 专业的密封产品行业信息网 | 橡胶膜片,夹布膜片,橡胶隔膜密封,泵阀设备密封膜片-衡水汉丰橡塑科技公司网站 | 桌上式超净工作台-水平送风超净工作台-上海康路仪器设备有限公司 | 尊享蟹太太美味,大闸蟹礼卡|礼券|礼盒在线预订-蟹太太官网 | 展厅设计公司,展厅公司,展厅设计,展厅施工,展厅装修,企业展厅,展馆设计公司-深圳广州展厅设计公司 | 道康宁消泡剂-瓦克-大川进口消泡剂供应商 | 【黄页88网】-B2B电子商务平台,b2b平台免费发布信息网 | 网站建设-高端品牌网站设计制作一站式定制_杭州APP/微信小程序开发运营-鼎易科技 | 合金耐磨锤头_破碎机锤头_郑州市德勤建材有限公司 | 纸箱抗压机,拉力机,脂肪测定仪,定氮仪-山东德瑞克仪器有限公司 | 东莞工厂厂房装修_无尘车间施工_钢结构工程安装-广东集景建筑装饰设计工程有限公司 | 三氯异氰尿酸-二氯-三氯-二氯异氰尿酸钠-优氯净-强氯精-消毒片-济南中北_优氯净厂家 | 济南网站建设|济南建网站|济南网站建设公司【济南腾飞网络】【荐】 | 废水处理-废气处理-工业废水处理-工业废气处理工程-深圳丰绿环保废气处理公司 | 安规_综合测试仪,电器安全性能综合测试仪,低压母线槽安规综合测试仪-青岛合众电子有限公司 |