vue权限治理体系

vue权限体系

背景治理体系平常都邑有权限模块,用来掌握用户能接见哪些页面和哪些数据接口。大多数治理体系的页面都长如许。

《vue权限治理体系》

左侧为菜单,分为两级,右侧为图表显现地区,有增编削查的按钮。

表的构造

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_auth_rule
-- ----------------------------
DROP TABLE IF EXISTS `t_auth_rule`;
CREATE TABLE `t_auth_rule` (
  `id_pk` bigint(20) NOT NULL AUTO_INCREMENT,
  `auth_id` varchar(128) NOT NULL COMMENT '权限Id',
  `pauth_id` varchar(128) DEFAULT NULL COMMENT '父级Id',
  `auth_name` varchar(255) NOT NULL COMMENT '权限称号',
  `auth_icon` varchar(255) NOT NULL COMMENT '权限图标',
  `auth_type` smallint(6) NOT NULL COMMENT '权限范例,BIT示意其属性\r\n            0x00示意可显现的菜单权限节点;\r\n            0x01示意一般节点',
  `auth_condition` text COMMENT '前提',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `is_menu` smallint(255) DEFAULT '0' COMMENT '是不是为菜单,0示意非,1示意是',
  `weight` int(11) NOT NULL DEFAULT '0' COMMENT '权重',
  `rule` varchar(256) DEFAULT NULL COMMENT '划定规矩途径重要对应菜单或要领的途径称号',
  `cr_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立时刻',
  `up_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时刻',
  PRIMARY KEY (`id_pk`),
  UNIQUE KEY `AK_auth_id` (`auth_id`)
) ENGINE=InnoDB AUTO_INCREMENT=264 DEFAULT CHARSET=utf8 COMMENT='权限划定规矩表,纪录权限相干的信息,权限以父子关联存在,菜单是权限的一种。';

SET FOREIGN_KEY_CHECKS = 1;


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_role_auth
-- ----------------------------
DROP TABLE IF EXISTS `t_role_auth`;
CREATE TABLE `t_role_auth` (
  `id_pk` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_id_fk` varchar(32) DEFAULT NULL COMMENT '角色id',
  `auth_id_fk` varchar(128) DEFAULT NULL COMMENT '权限id',
  `aa` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id_pk`)
) ENGINE=InnoDB AUTO_INCREMENT=77 DEFAULT CHARSET=utf8 COMMENT='角色与权限的关联表';

SET FOREIGN_KEY_CHECKS = 1;

轻微解释一下表构造,t_auth_rule 表用来存储对应的权限菜单,平常来说,菜单分为一级和二级菜单,rule字段对应前端的路由划定规矩;而按钮为第三级,rule对应的是接口url地点。
t_role_auth 表为角色权限关联表,一个角色具有哪些权限是经由过程这张表查出来的。固然另有一个role表,另有一个账号表,账号内外有一个role的外键。
如许就是一个账号 –> 角色 –> 权限的关联。

关于菜单的权限,经由过程路由表婚配

// 当地写好路由列表(须要举行动态婚配的)
export const routerList: Array<RouteConfig> = [
  // 首页
  {
    path: '/',
    name: '_home',
    redirect: '/home',
    component: Layout,
    meta: {
      hideInMenu: true,
      notCache: true
    },
    children: [
      {
        path: 'home',
        name: 'home',
        meta: {
          hideInMenu: true,
          title: '首页',
          notCache: true,
          icon: 'md-home'
        },
        component: () => import('@/views/overview-operations/data-center/DataCenter.vue')
      }
    ]
  }
]

// 担任将背景返回的 菜单列表 转成vue-router所须要的 router list
export function toRouterComponent(menuList: Array<any>) {
  if (!menuList.length) return []

  let routerArr = [];
  for (let j = 0; j < menuList.length; j++) {
    let obj;
    let firstIndex = routerList.findIndex(i => i.path === menuList[j].url); // 一级菜单
    if (firstIndex !== -1) {
      let children: Array<RouteConfig> = []
      obj = {
        path: routerList[firstIndex].path,
        component: routerList[firstIndex].component,
        redirect: routerList[firstIndex].redirect,
        name: routerList[firstIndex].name,
        meta: routerList[firstIndex].meta,
        children
      };

      // 假如有子菜单
      if (menuList[j].children && menuList[j].children.length) {
        for (let k = 0; k < menuList[j].children.length; k++) {
          const _children = routerList[firstIndex].children!
          let secondIndex = _children.findIndex(i => {
            let fullpath = '';
            if (routerList[firstIndex].path === '/') {
              fullpath = `${routerList[firstIndex].path}${i.path}`;
            } else {
              fullpath = `${routerList[firstIndex].path}/${i.path}`;
            }
            return fullpath === menuList[j].children[k].url;
          });
          if (secondIndex !== -1) {
            obj.children.push(_children[secondIndex]);
          }
        }
      }
    }

    if (obj) {
      routerArr.push(obj);
    }
  }

  return routerArr;
}

// 依据菜单权限,猎取路由数组
// 当地只保存背景返回的菜单,在页面革新的时刻从当地拿到菜单从新挪用toRouterComponent天生 路由数组
export function getRouterList() {
  if (!storage.get('username')) {
    storage.set('menuTree', ''); // 清空菜单权限数据
  }
  let menuList = storage.get('menuTree') ? storage.get('menuTree') : [];

  const routerArr = toRouterComponent(menuList);
  return routerArr;
}

menuList,菜单数组(或对象), 由背景返回; routerList为前端定义的路由表;遍历routerList,假如routerList的path在menuMap里能找到的话,就示意该路由存在。末了天生一个过滤后的路由表,用vue供应的addRoutes要领动态增加到路由中,并把过滤后的路由表存到当地。

在页面革新的时刻,从当地猎取路由表,增加到路由表中,代码以下,constRouterArr为基本路由表,比方登录,404等

注重这一步有个题目,因为我写的storage库用了JSON.stringify,把路由表中的component(现实为一个函数)丧失了,所以在从当地猎取路由的时刻,还要从新天生一个新的路由表,从新把component加上去,即把上面的addrouters从新实行一遍

关于按钮的权限

if (res.data.auth_rule_map) {
    let obj = {}
    Object.keys(res.data.auth_rule_map).forEach(i => {
      // 将一切的按钮放到一个obj里 key 为接口地点  
      if (res.data.auth_rule_map[i].is_menu === 0) {  // 假如是按钮
        obj[res.data.auth_rule_map[i].rule] = 1
      }             
    })
    storage.set("btnList", obj);
    storage.set("menuTree", res.data.auth_rule_map);
}

auth_rule_map为接口返回权限map,把按钮的权限过滤出来存到当地
将map增加到每一个路由组件的data里,(这里有一个题目,怎样推断一个组件是不是是路由组件),现在想到的是经由过程组件name来推断,把一切的路由组件放到一个数组里做推断。

在组件内部的按钮上加上v-if,假如this.uri__里的uri在uriMap里存在就显现。
也能够经由过程要领来推断,以下面的__isBtnShow,不仅能够掌握按钮的显现隐蔽,还能够掌握其款式,比方色彩等,越发天真,引荐运用要领来掌握

uri = {
    ADD_MEMBER: '/api/add_member'
}

export default function install (Vue) {
  const uriMap = storage.get('btnList')
  //uriMap['/admin/api/auth_rule/update_auth_rule.action'] = 1
  Vue.mixin({
    created() {
      const arr = ['MemberManage', 'PayManage', '...']
      if (arr.indexOf(this.$options.name) !== -1) {
        this.dataUri__ = uriMap
        this.uri__ = uri  
      }
    },
    data() {
      return {
        dataUri__: {}
      }
    },
    methods: {
      __isBtnShow(uri) {
        return uriMap[uri] ? 'display: inline-block' : 'display: none'
      },
    }
  })
}

<Button v-if="dataUri__[uri__.ADD_MEMBER]">增加会员</Button>

// 经由过程要领来掌握,越发天真
<Button :style="__isBtnShow(uri__.ADD_MEMBER)">增加会员</Button>

登出的题目

**登出后要清空缓存,routerArr,btnList 等。
因为之前登录,挪用addRouter把权限上个账号的路由表加进去了,所以登出后要location.reload()一次,从新实例化路由表,去掉动态增加的路由,只保存基本路由。
location.reload()体验不是太好,然则vue-router没有供应动态删除路由的api,比方 deleteRouter。**

同时登两个账号,致使革新页面的时刻,前者页面的当地缓存被掩盖,权限菜单等数据发生变化,路由表也发生变化

能想到的解决要领是存一个loginIndex 来示意登录账号的个数,比方第一次登录的时刻存一个loginIndex=0, 背面存数据的时刻都把这个参数带上;背面登多个账号的时刻个loginIndex++,如许localStorage的key就是一个动态的(如许照样不可)
最简朴的要领是存到localStorage里,只要登出才会清空缓存,只能登一个账号。

    原文作者:韦磊
    原文地址: https://segmentfault.com/a/1190000017921971
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞