使用vue-element-admin整合方案------許可權篇

陌上寒の發表於2019-04-02

  許可權控制的思路:

      在router資料夾中的index.js檔案中有一份路由表,表示每個路由的可訪問許可權.使用者登入後,通過token獲取使用者的role,動態根據使用者的role算出有許可權的路由,通過router.addRoutes動態掛載路由.

      每一個後臺的請求不管是 get 還是 post 都會讓前端在請求 header裡面攜帶使用者的 token,後端會根據該 token 來驗證使用者是否有許可權執行該操作。若沒有許可權則丟擲一個對應的狀態碼,前端檢測到該狀態碼,做出相對應的操作。

具體實現

  1. 建立vue例項將vue-router掛載,此時vue-router掛載一些登入或者不用許可權的公用的頁面
  2. 使用者登入後,獲取role,,將role和路由表每個頁面的需要的許可權作比較,生成終端使用者可訪問的路由表
  3. 呼叫router.addRoutes(store.getters.addRouters)新增使用者可訪問的路由
  4. 使用vuex管理路由表,根據vuex中可訪問的路由渲染側邊欄元件

先編一個路由表

// router.js
import Vue from 'vue';
import Router from 'vue-router';

import Login from '../views/login/';
const dashboard = resolve => require(['../views/dashboard/index'], resolve);
//使用了vue-routerd的[Lazy Loading Routes
](https://router.vuejs.org/en/advanced/lazy-loading.html)

//所有許可權通用路由表 
//如首頁和登入頁和一些不用許可權的公用頁面
export const constantRouterMap = [
  { path: '/login', component: Login },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    name: '首頁',
    children: [{ path: 'dashboard', component: dashboard }]
  },
]

//例項化vue的時候只掛載constantRouter
export default new Router({
  routes: constantRouterMap
});

//非同步掛載的路由
//動態需要根據許可權載入的路由表 
export const asyncRouterMap = [
  {
    path: '/permission',
    component: Layout,
    name: '許可權測試',
    meta: { role: ['admin','super_editor'] }, //頁面需要的許可權
    children: [
    { 
      path: 'index',
      component: Permission,
      name: '許可權測試頁',
      meta: { role: ['admin','super_editor'] }  //頁面需要的許可權
    }]
  },
  { path: '*', redirect: '/404', hidden: true }
];

通過meta標籤來標示頁面訪問的許可權. 如meta:{role: ['admin','super_editor'] }

注意:404頁面一定要最後載入,如果放在constantRouterMap一同宣告404,後面的頁面都會被攔截到404頁面

main.js

// main.js
router.beforeEach((to, from, next) => {
  if (store.getters.token) { // 判斷是否有token
    if (to.path === '/login') {
      next({ path: '/' });
    } else {
      if (store.getters.roles.length === 0) { // 判斷當前使用者是否已拉取完user_info資訊
        store.dispatch('GetInfo').then(res => { // 拉取info
          const roles = res.data.role;
          store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可訪問的路由表
            router.addRoutes(store.getters.addRouters) // 動態新增可訪問路由表
            next({ ...to, replace: true }) // hack方法 確保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
          })
        }).catch(err => {
          console.log(err);
        });
      } else {
        next() //當有使用者許可權的時候,說明所有可訪問路由已生成 如訪問沒許可權的全面會自動進入404頁面
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登入白名單,直接進入
      next();
    } else {
      next('/login'); // 否則全部重定向到登入頁
    }
  }
});

 

store/permission.js

// store/permission.js
import { asyncRouterMap, constantRouterMap } from 'src/router';

function hasPermission(roles, route) {
  if (route.meta && route.meta.role) {
    return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    return true
  }
}

const permission = {
  state: {
    routers: constantRouterMap,
    addRouters: []
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers;
      state.routers = constantRouterMap.concat(routers);
    }
  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const { roles } = data;
        const accessedRouters = asyncRouterMap.filter(v => {
          if (roles.indexOf('admin') >= 0) return true;
          if (hasPermission(roles, v)) {
            if (v.children && v.children.length > 0) {
              v.children = v.children.filter(child => {
                if (hasPermission(roles, child)) {
                  return child
                }
                return false;
              });
              return v
            } else {
              return v
            }
          }
          return false;
        });
        commit('SET_ROUTERS', accessedRouters);
        resolve();
      })
    }
  }
};

export default permission;

通過使用者的許可權和之前router.j裡asyncRouterMap每個頁面所需許可權做匹配,左後返回該使用者能訪問的那些路由.

 

相關文章