前端許可權控制系統的實現思路

lerryteng發表於2018-05-29

一、專案主體

  • 管理平臺(代稱為ManagePlatform、MP)
  • 一級選單(代稱M)
  • 二級選單(代稱m)

結構圖:

前端許可權控制系統的實現思路

二、應用場景

不同使用者擁有不同的選單許可權:

  • 管理員(manageUser)擁有可見全部選單的許可權

前端許可權控制系統的實現思路

  • 使用者1(user1)擁有可見M1下的全部選單的許可權

前端許可權控制系統的實現思路

  • 使用者2(user2)擁有可見M1和M2下的全部選單的許可權

前端許可權控制系統的實現思路

  • 使用者3(user3)擁有可見M1、M2下全部及M3的m31選單許可權

前端許可權控制系統的實現思路

三、實現思路

許可權控制:

  1. 導航欄選單是否可見
  2. 校驗url能否跳轉

服務端:

  1. 介面返回當前使用者的許可權資料,並實際選單結構保持一致(MP中包含M1、M2、M3,M1中包含m11、m12,...)
  2. 其中每個選單包含id(選單id)、name(選單名稱)、children(子集選單)等必要屬性

前端:

  1. 路由預設配置全部的選單,但均為隱藏狀態(登入和首頁無許可權,無需限制)
  2. 通過介面獲取到該使用者的許可權資料,並與預設路由進行比對,將對應選單部分設定為可顯示(有許可權)
  3. 將選單所有id儲存到本地list,在路由跳轉之前校驗此路由的id是否包含在list中,如果有,則執行跳轉,否則進入到首頁(表示沒有許可權)

四、程式碼模擬

預設路由routes:

export default [
  {
    path: '/M1',
    redirect: '/M1/m11',
    component: Layout,
    name: 'M1選單',
    meta: {
      extraMenuId: 1,
      hidden: true
    },
    children: [{
      path: '/M1/m11',
      name: 'm11選單',
      component(resolve) {
        require(['@views/M1/m11'], resolve);
      },
      meta: {
        extraMenuId: 2,
        hidden: true,
      }
    }, {
      path: '/M1/m12',
      name: 'm12選單',
      component(resolve) {
        require(['@views/M1/m12'], resolve);
      },
      meta: {
        extraMenuId: 3,
        hidden: true,
      }
    }]
  },
  {
    path: '/M2',
    redirect: '/M2/m21',
    component: Layout,
    name: 'M2選單',
    meta: {
      extraMenuId: 4,
      hidden: true
    },
    children: [{
      path: '/M2/m11',
      name: 'm21選單',
      component(resolve) {
        require(['@views/M2/m21'], resolve);
      },
      meta: {
        extraMenuId: 5,
        hidden: true,
      }
    }, {
      path: '/M2/m22',
      name: 'm22選單',
      component(resolve) {
        require(['@views/M2/m22'], resolve);
      },
      meta: {
        extraMenuId: 6,
        hidden: true,
      }
    }]
  },
  {
    path: '/M3',
    redirect: '/M3/m31',
    component: Layout,
    name: 'M3選單',
    meta: {
      extraMenuId: 7,
      hidden: true
    },
    children: [{
      path: '/M3/m31',
      name: 'm31選單',
      component(resolve) {
        require(['@views/M3/m31'], resolve);
      },
      meta: {
        extraMenuId: 8,
        hidden: true,
      }
    }, {
      path: '/M3/m32',
      name: 'm32選單',
      component(resolve) {
        require(['@views/M3/m32'], resolve);
      },
      meta: {
        extraMenuId: 9,
        hidden: true,
      }
    }, {
      path: '/M3/m33',
      name: 'm33選單',
      component(resolve) {
        require(['@views/M3/m33'], resolve);
      },
      meta: {
        extraMenuId: 9,
        hidden: true,
      }
    }]
  },
  {
    path: '/login',
    name: '登入',
    component(resolve) {
      require(['@views/login'], resolve);
    },
    meta: {
      hidden: true
    }
  },
  {
    path: '/home',
    name: '首頁',
    component(resolve) {
      require(['@views/home'], resolve);
    },
    meta: {
      hidden: true
    }
  },
  {
    path: '*',
    redirect: '/home',
    meta: {
      hidden: true
    }
  }
]
複製程式碼

選單id資料menuIdList與路由routes匹配:

// 因管理端選單展示只展示兩層,故只需遍歷前兩層路由
routes.forEach((item) => {
  if (menuIdList.indexOf(item.meta.extraMenuId) >= 0) {
    item.meta.hidden = false;
    if (item.children && item.children.length) {
      item.children.forEach((child) => {
        if (menuIdList.indexOf(child.meta.extraMenuId) >= 0) {
          child.meta.hidden = false;
        }
      })
    }
  }
});
複製程式碼

公共方法判斷id是否存在:

/**
 * 判斷menuId是否存在與Localtorage中
 * @param menuId
 */
export function getMenuAuth(menuId) {
  const menuIdList = JSON.parse(getMenuIdList());
  return menuIdList.indexOf(menuId) >= 0;
}
複製程式碼

路由守衛校驗:

router.beforeEach((to, from, next) => {
  // 判斷是否已登入,未登入則進入登入頁面
  if (getToken()) {
    if (to.path === '/login') {
      next();
    } else {
      if (to.path === '/' || to.path === '/home') {
        next();
        return;
      }
      // url路由許可權校驗,沒有許可權則進入home頁面
      if (getMenuAuth(to.meta.extraMenuId)) {
        next();
      } else {
        next('/home');
      }
    }
  } else {
    next('/login');
  }
})
複製程式碼

以上僅為專案開發過程中的個人思路,如有更好的想法思路請在評論區留言,謝謝!

相關文章