欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2020年04月23日 09:38:40   作者:lxcan  
這篇文章主要介紹了淺談vue權(quán)限管理實(shí)現(xiàn)及流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、整體思路

后端返回用戶權(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,此時會進(jìn)入路由攔截根據(jù) token 獲取用戶權(quán)限列表。
(3)全局路由攔截,根據(jù)當(dāng)前用戶有沒有 token 和 權(quán)限列表進(jìn)行相應(yīng)的判斷和跳轉(zhuǎn),當(dāng)沒有 token 時跳到 login,當(dāng)有 token 而沒有權(quán)限列表時去發(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 === [],匹配的是空路由,此時需要重定向到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)時沒有權(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,此時還沒有 token,匹配的是空路由,我們重定向到登錄頁 next({ path: '/login' });
(2)用戶在登錄頁刷新頁面,也會進(jìn)入路由攔截,此時匹配的是 login 路由,而 login 路由是不需要登錄驗(yàn)證的(requiresAuth 為空或者 false),所以直接跳過執(zhí)行 next();
(3)用戶在登錄頁輸入了用戶名和密碼,登錄成功,保存了 token,跳轉(zhuǎn)到 /home 路由;
(4)此時進(jìn)入路由攔截,已經(jīng)有 token了,但是還沒有用戶權(quán)限 permissionList,然后發(fā)請求獲取用戶權(quán)限列表,得到權(quán)限后 next({ path: to.path, query: to.query }); 繼續(xù)往下走;
(5)再次進(jìn)入路由攔截,此時有 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 路由攔截時,多次執(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 中存儲的各種信息,刷新頁面是最保險的。

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

四、總結(jié)

缺點(diǎn):
全局路由守衛(wèi)里,每次路由跳轉(zhuǎn)都要做判斷;
每次刷新頁面,需要重新發(fā)請求獲取用戶權(quán)限;
退出登錄時,需要刷新一次頁面將動態(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Vue3怎么使用element-plus

    詳解Vue3怎么使用element-plus

    本文主要介紹了Vue3怎么使用element-plus,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Vuex modules模式下mapState/mapMutations的操作實(shí)例

    Vuex modules模式下mapState/mapMutations的操作實(shí)例

    這篇文章主要介紹了Vuex modules 模式下 mapState/mapMutations 的操作實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Vue項(xiàng)目請求超時處理方式

    Vue項(xiàng)目請求超時處理方式

    這篇文章主要介紹了Vue項(xiàng)目請求超時處理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • vue.config.js中配置configureWebpack和chainWebpack以及一些常用的配置

    vue.config.js中配置configureWebpack和chainWebpack以及一些常用的配置

    configureWebpack和chainWebpack都是Vue CLI中用于修改Webpack配置的工具,configureWebpack可以通過對象或函數(shù)修改配置,簡單直接;chainWebpack則使用WebpackChainAPI,適合復(fù)雜配置,兩者可以結(jié)合使用,以達(dá)到更精細(xì)的配置需求,幫助開發(fā)者優(yōu)化項(xiàng)目構(gòu)建
    2024-10-10
  • VUE使用draggable實(shí)現(xiàn)組件拖拽

    VUE使用draggable實(shí)現(xiàn)組件拖拽

    這篇文章主要為大家詳細(xì)介紹了VUE使用draggable實(shí)現(xiàn)組件拖拽,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Vue中watch監(jiān)聽屬性新舊值相同的問題解決方案

    Vue中watch監(jiān)聽屬性新舊值相同的問題解決方案

    這篇文章主要給大家分享了Vue中watch監(jiān)聽屬性新舊值相同問題解決方案,如果有遇到相同問題的朋友,可以參考閱讀本文
    2023-08-08
  • Vue自定義鈴聲提示音組件的實(shí)現(xiàn)

    Vue自定義鈴聲提示音組件的實(shí)現(xiàn)

    這篇文章主要介紹了Vue中自定義一個鈴聲提示音組件的實(shí)現(xiàn)以及使用方法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Vue有一定幫助,需要的可以參考一下
    2022-01-01
  • Vue封裝的可編輯表格插件方法

    Vue封裝的可編輯表格插件方法

    今天小編就為大家分享一篇Vue封裝的可編輯表格插件方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • Vue實(shí)現(xiàn)定位并解決內(nèi)存泄漏

    Vue實(shí)現(xiàn)定位并解決內(nèi)存泄漏

    Vue.js?是一個流行且強(qiáng)大的?JavaScript?框架,它允許我們構(gòu)建動態(tài)和交互式?Web?應(yīng)用程序,本文我們將深入探討?Vue.js?應(yīng)用程序中內(nèi)存泄漏的原因,并探索如何定位和修復(fù)這些問題的有效策略,希望對大家有所幫助
    2023-09-09
  • Antd表格滾動 寬度自適應(yīng) 不換行的實(shí)例

    Antd表格滾動 寬度自適應(yīng) 不換行的實(shí)例

    這篇文章主要介紹了Antd表格滾動 寬度自適應(yīng) 不換行的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10

最新評論