Vue.js快速入门之七:系统权限管理

        每个系统项目中,都离不开权限的管理。有些小项目为了快速开发,可能会省略权限的处理;但中大型项目无法回避,中大型系统使用的人员比较繁杂,每个人身处不同职位或职权,所看到信息是不一样的。

        权限管理,一般是先建“角色”,给角色添加某些栏目显示权限,或赋予增删改权限,再将“角色”指派给对应用户。一个用户可能只有一个角色,或多个角色,这样该用户则拥有了这些“角色”的权限集合。

  • 如A用户的角色为“超级管理员”,则拥有所有权限,可任意查看系统任何页面和功能;
  • 如B用户的角色为运维人员,则只能看到运维部分功能页面,以及查看和编辑的权限。

        下面我们通过代码,来处理栏目显示的权限,来了解前端是否何处理权限问题的。

一、新建db.js,存储模拟数据

        前面几篇已介绍了如何使用mockjs以及定义模拟数据,这里不再阐述,代码如下:

import { Random } from 'mockjs'

const DBdata = new Map();

DBdata.set('栏目列表', [
  {
    "name": "首页",
    "path": "/home/index",
    "permission": ["view-home"],
    "icon": "el-icon-data-line"
  },
  {
    "name": "栏目管理",
	"path": "/category/index",
    "permission": ["view-category"],
	"icon": "el-icon-data-board",
  },
  {
    "name": "用户管理",
    "path": "/user/index",
    "permission": ["view-user"],
    "icon": "el-icon-pie-chart"
  },
  {
    "name": "角色管理",
	"path": "/role/index",
    "permission": ["view-role"],
	"icon": "el-icon-data-analysis"
  },
  {
    "name": "设置管理",
	"path": "/setting/index",
    "permission": ["view-setting"],
	"icon": "el-icon-collection-tag",
  }
]);

DBdata.set('用户信息', {
	username: 'test',
	avatar: '',
	company: '',
	rolename: '管理员',
	roles: ['view-home', 'view-category', 'view-user', 'view-setting']
});

export default DBdata;

        如上代码,如果用户roles列表中,将view-setting去除,则该用户则无显示系统设置的权限,该栏目也不会显示。

二、创建模拟接口数据

        新建mock/index.js,用来定义模拟接口,代码如下:

import { mock } from 'mockjs'
import DBData from '@/db'

/**
 * 获取栏目列表信息
 */
mock('/api/user/info', 'get', (request, response) => {
  return {
  	code: 200,
		data: {
			userinfo: DBData.get('用户信息').map(item => item),
			menu: DBData.get('栏目列表').map(item => item),
			token: 'kjadfakldho134koadf82389adfklkj123409jaldkfaljk2134j'
		},
		message: 'success'
  };
});

三、创建API请求

        api中创建index.js,创建接口请求功能函数,对axios请求进行封装的request.js文件,前端篇幅已讲解,代码直接拿过来使用即可。

import Service from '@/utils/request'

export const getUserInfo = () => {
  return Service.get('/api/user/info', {});
}

四、定义store状态管理器

        store状态管理器中,添加相关数据。以下主要为两项功能:

  1. 通过getters计算出拥有显示权限栏目列表
  2. 添加actions业务功能函数,在路由勾子函数中,添加权限过滤,如不在权限内的则无法通过路由直接访问。

4.1 state定义变量

        在store中state.js中定义相应变量,代码如下:

const state = {
  //栏目列表
  category: [],
  //访问令牌
  token: '',
  //用户信息
  userInfo: {},
  //角色列表
  roles: []
}

export default state;

4.2 getters定义相应计算属性

        getters.js文件中定义,这里重点是categoryRoleList函数,返回可显示的栏目数据,栏目列表中获取该列表数据进行显示。代码如下:

const getters = {
  userInfo(state){
    let { username, company } = state.userInfo;
    return { username, company };
  },
  roleList(state){
	return state.roles;
  },
  categoryList(state){
	return state.category;
  },
  //获取可显示的栏目列表
  categoryRoleList(state){
    return state.category.filter(
	  item => Array.isArray(item['permission'])&&
	  (
	    item.permission.length==0 ||      //没有权限信息的,直接通过
	    state.roles.filter(sub => item.permission.includes(sub.roleName)).length>0     //在权限数组中的,可以通过
	  )
    );
  }
}
export default getters;

4.3 mutationsType类型定义

        mutationsType.js文件中定义以下常量值,代码如下:

export const USERINFO = "USERINFO";
export const TOKEN = "TOKEN";
export const ROLES = "ROLES";
export const CATEGORY_LIST = "CATEGORY_LIST";

4.4 mutations.js文件

        mutations定义函数修改变量值,代码如下:

import { USERINFO, TOKEN, ROLES, CATEGORY_LIST } from './../mutationsType'

const mutations = {
  [USERINFO](state, param){
    state.userInfo = param;
  },
  [TOKEN](state, param){
    state.token = param;
  }
  [CATEGORY_LIST](state, param){
    state.category = param;
  },
  [ROLES](state, param){
    state.roles = param;
  }
}
export default mutations;

4.5 actions定义业务逻辑函数

        这里只仅使用了vuex状态管理器进行存储数据,需要做数据可持久化,可以增加localstorage或sessionstorage进行本地存储,页面刷新或重新访问页面时,把本地数据重新缓存到vuex中。

        这里重点是checkRolesRoutePermission业务函数,放到router的勾子函数中,用来阻止无访问权限的路由跳转。代码如下:

import { USERINFO, TOKEN, ROLES, CATEGORY_LIST } from './../mutationsType'

const actions = {
  //登录信息
  loginInfo({commit}, params){
	 commit(USERINFO, params.userinfo);
	 commit(TOKEN, params.token);
	 commit(ROLES, params.roles);
	 commit(CATEGORY_LIST, params.menu);
  },
	//检测路由是否有权限
	checkRolesRoutePermission({ commit, getters }, param){
	  let DGFilter = (_child, _path) => {
				return Array.isArray(_child) && _child.length>0 && _child.filter( item => item.path == _path || DGFilter(item['children'], _path) ).length > 0;
		  };
	  return new Promise((resolve, reject) => {
			let { categoryList, roleList } = getters,
				//筛选出当前路径对应的一线栏目
				filterMenuList = categoryList.filter(
				  item => item.path == param || DGFilter(item['children'], param)
				);
			//如果菜单列表中有筛选到数据,进入处理,否则放行
			if(filterMenuList.length>0){
			  let _permission = filterMenuList[0]['permission'];
			  //如果菜单列表中权限列表长度大于0,表示有权限数据,进入处理, 否则放行
			  if(Array.isArray(_permission)&&_permission.length>0){
					//判断角色列表中,是否存在该该权限,存在则可放行,不存在,无法通行
					if( roleList.filter(item => _permission.includes(item.roleName)).length>0 ){
						resolve();
					}else{
						reject({
							code: 404,
							message: "当前页面无访问权限"
						});
					}
			  }else{
					resolve();
			  }
	  });
	},
}

export default actions;

五、路由中添加校验权限

        在router目录中创建index.js文件,定义好系统路由,并通过勾子函数对路由进行过滤处理。通过路由进行页面跳转时,如没有访问权限,则直接跳转到无访问权限页面。getters中已获取有权限访问的栏目列表,则从栏目中访问无权限页面已被屏蔽,如在浏览器地址栏直接通过路由访问,则会通过以下代码中,路由卫士进行拦截。

import Vue from 'vue'
import Router from 'vue-router'
import store from '@/store'

//......

let _router = new Router({
  routes: [
    {
      path: '/',
      name: 'Index',
      component: Index,
    },
    //......
    {
      path: '/no-permission',
      name: 'Error405',
      component: Error405,
    },
    {
      path: '*',
      name: 'Error404',
      component: Error404,
    },
  ]
});

_router.beforeEach((toRoute, fromRoute, next) => {
 //检测路由是否权限
  store.dispatch('checkRolesRoutePermission', toRoute.path).then(res => {
    if(toRoute.path!=fromRoute.path){
      next();
    }
  }).catch(e => {
    if(toRoute.path!=fromRoute.path){
      next(e.code==405?'/no-permission':'/error');
    }
  });
});

export default _router;

六、用户信息和菜单权限获取

6.1 实现登录功能

        在用户登录成功时,就可以获取到用户的角色信息,以及栏目列表信息。将用户信息,访问令牌,权限数据等信息存储到Store状态管理器中代码如下:

<script>
  import { getUserInfo } from '@/api/index'

  export default {
    data(){
      return {

      }
    },
	methods: {
		//登录事件
		login(){
			//do something....

			this.updateUserinfo();
		},
		//获取用户信息
		updateUserinfo(){
			getUserInfo({
				//传入登录信息
				//...
			}).then(res => {
				if(res.code==200){
                    //将用户信息存储到vuex中
					this.$store.dispatch('loginInfo', {
						userinfo: res.data['userinfo'],
						token: res.data['token'],
						menu: res.data['menu'],
						roles: res.data['userinfo']['roles']
					});
				}

			});

		}
		
	}
  }
</script>

        以上登录页面只展示了业务部分代码,dom部分大家可以使用element-ui组合快速搭建。

6.2 栏目列表显示

        显示已进行权限过滤的栏目列表,代码如下:

<template>
<div class="category-list">
	<div class="list-item" 
		v-for="(item, index) in categoryRoleList" 
		:key="index">
		<h3>{
   
   {item.name}}</h3>
	</div>
</div>
</template>

<script>
  import { mapGetters } from 'vuex'

  export default {
    data(){
      return {

      }
    },
	computed: {
		//获取可显示栏目列表
		...mapGetters(['categoryRoleList'])
	},
	methods: {
		
	}
  }
</script>

以上讲解的是通过后台动态获取所有栏目及其所对应的权限,以及动态获取用户的角色信息,进行相互匹配进行的权限显示和访问限制。以上仅供大家参考与学习。

猜你喜欢

转载自blog.csdn.net/jiciqiang/article/details/115548377
今日推荐