前端菜單及按鈕權限攔截,實現方案及思路


【前言】

此實現方案基於vue框架,並需要依賴vue項目相關的庫,router、store等等;前端同學要與后端同學協商,常規是讓后端返回一個樹結構的菜單數據,並且將所有的涉及權限控制的頁面path給到后端,如果是按鈕,需要把所有的按鈕 code 碼統一下,這是前期工作,很重要。

 

首先,main.js 引入相關文件

import Vue from 'vue';
import App from './App.vue';
import router from '@/router';
import store from '@/store';
import '@/plugins/permission';
import '@/plugins/directives';
import '@/plugins/auth';

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app');

 

在main.js同目錄創建 plugins 文件,作為公共文件,在plugins 里創建 permission.js。

import router from @/router';
import store from '@/store';
import { hasMenuAuth } from '@/plugins/auth';


router.beforeEach(async (to, from, next) => {
    store.dispatch('auth/getAuthData');
  // 校驗菜單權限
      if (hasMenuAuth(to.path)) {
        next();
      } else {
        next({ path: '/' });
      }
});

 

在store目錄里創建 auth.js ,getUserMenuList 為定義的接口 api

import { getUserMemuList } from @/api/auth';

/**
 * 樹型數據轉列表
 * @param {*} tree 樹型數據
 * @param {*} childrenKey 子節點列表鍵
 */
const convertTreeToList = (tree, childrenKey = 'children') => {
  if (!Array.isArray(tree)) return [];
  // 所有的菜單集合
  let list = [];
  // 遞歸查找
  let fn = data => {
    let origin = data.slice(0);
    list = list.concat(origin);
    data.forEach(item => {
      let children = item[childrenKey];
      Array.isArray(children) && fn(children);
    });
  };
  fn(tree);
  return list;
};

const state = {
  // 路由菜單權限
  routeAuthList: {},
  // 按鈕權限列表
  authList: {}
  }
};

const mutations = {
   // 菜單權限列表
  SET_ROUTE_AUTH_LIST(state, data) {
    // 路由權限集合
    let routeAuthList = {};
    // 按鈕權限集合
    let buttonAuthList = {};
    data.map(item => {
      // 將所有的 path 存入對象中
      if (item.path) {
        routeAuthList[item.path] = true;
      }
      // 將所有的 code 存入對象中
      if (item.code) {
        buttonAuthList[item.code] = true;
      }
    });
    state.routeAuthList = routeAuthList;
    state.authList = buttonAuthList;
  },
};

const actions = {
  // 獲取菜單列表
  getAuthData({ commit }) {
    return getUserMemuList().then(({ data }) => {
      let list = convertTreeToList(data);
      commit('SET_ROUTE_AUTH_LIST', list);
      return data;
    });
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions
};

 

這時,例如在頁面中打印,效果是這樣的

 

 至此,已經將該用戶下所屬的權限拉取,並存儲在 store 里了,可以全局訪問使用。

前面 permission 文件里引用的 hasMenuAuth 方法,需要在 plugins 目錄中,創建 auth.js, 並定義下此方法。

import Vue from 'vue';
import store from '@/store';

/**
 * 校驗路由是否有權限
 * @param {Array} path 權限
 * @return {boolean}
 */
export function hasMenuAuth(path) {
  // 無權限配置無需校驗
  if (!(path && path.length)) return true;
  const list = store.state.auth.routeAuthList;
  // 校驗是否有權限
  let auth = list[path] ? true : false;
  return auth;
}

/**
 * 校驗按鈕是否有權限
 * @param {*} list 權限配置
 */
export function hasBtnAuth(list) {
  // 無權限配置,不校驗
  if (!list || !list.length) return true;
  const authList = (store.getters && store.getters.authList) || {};
  let hasPermission = false;
  // // 遍歷數組,如果有一個code碼存在,則返回true
  list.map(item => {
    if (authList[item]) hasPermission = true;
  });
  return hasPermission;
}

// 掛在權限校驗方法
Vue.has = hasBtnAuth;
Vue.prototype.$has = hasBtnAuth;

 

到此處,整個項目路由的攔截就實現了,但目前只攔截了 path,但有頁面的按鈕,雖然點擊后由於做了攔截,讓其跳到了默認頁。但按鈕的還是展示的,這時就需要用到 上面的 hasBtnAuth 方法了。

由於已經在vue實例上掛載了 $has,只需在 vue 組件中使用就好了,可以用在節點里,也可在方法里

 

當然按鈕的顯隱,還有進階版方法,那就是可以注冊個自定義指令,在 plugins 目錄下創建 directives.js 文件

/**
 * 按鈕權限指令
 * 根據vuex下的auth模塊的authList按鈕code列表判斷權限
 */
import Vue from 'vue';
import store from '@/store';

/**
 * 校驗是否有權限,無權限刪除dom節點
 * @param {*} el dom元素
 * @param {*} binding 綁定數據
 */
function hasAuth(el, binding) {
  const { value } = binding;
  const authList = (store.getters && store.getters.authList) || [];
  if (value && value instanceof Array && value.length > 0) {
    const list = value;
    let hasPermission = false;
    // 遍歷數組,如果有一個code碼存在,則返回true
    list.map(item => {
      if (authList[item]) hasPermission = true;
    });
    if (!hasPermission && value && value.length) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  }
}

let auth = {
  inserted: hasAuth,
  update: hasAuth
};

const install = function(Vue) {
  Vue.directive('auth', auth);
};

Vue.use(install);

 

現在,使用起來更方便了

 

好了,具體實現方法就是這些,有些地方簡述了,但幾乎涉及的地方都涉及到了,歡迎指出不足,我也會補全

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM