• 前端菜单及按钮权限拦截,实现方案及思路


    此实现方案基于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);

    现在,使用起来更方便了

    好了,具体实现方法就是这些,有些地方简述了,但几乎涉及的地方都涉及到了,欢迎指出不足,我也会补全

  • 相关阅读:
    如何编写 maptalks plugin
    maptalks 如何加载 ArcGIS 瓦片图层
    vue 地图可视化 maptalks 篇
    个人博客如何开启 https
    vue.js多页面开发环境搭建
    vue 自动化部署 jenkins 篇
    virtualbox ubuntu 安装 openssh-server
    从零开始学 Spring Boot
    数据结构
    vue 转换信息为二进制 并实现下载
  • 原文地址:https://www.cnblogs.com/wx3091/p/16055599.html
Copyright © 2020-2023  润新知