1. 程式人生 > 其它 >客戶端選單及按鈕許可權的實現方案及思路

客戶端選單及按鈕許可權的實現方案及思路

此實現方案基於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);

現在,使用起來更方便了

 

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