每个系统项目中,都离不开权限的管理。有些小项目为了快速开发,可能会省略权限的处理;但中大型项目无法回避,中大型系统使用的人员比较繁杂,每个人身处不同职位或职权,所看到信息是不一样的。
权限管理,一般是先建“角色”,给角色添加某些栏目显示权限,或赋予增删改权限,再将“角色”指派给对应用户。一个用户可能只有一个角色,或多个角色,这样该用户则拥有了这些“角色”的权限集合。
下面我们通过代码,来处理栏目显示的权限,来了解前端是否何处理权限问题的。
前面几篇已介绍了如何使用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中创建index.js,创建接口请求功能函数,对axios请求进行封装的request.js文件,前端篇幅已讲解,代码直接拿过来使用即可。
- import Service from '@/utils/request'
-
- export const getUserInfo = () => {
- return Service.get('/api/user/info', {});
- }
store状态管理器中,添加相关数据。以下主要为两项功能:
在store中state.js中定义相应变量,代码如下:
- const state = {
- //栏目列表
- category: [],
- //访问令牌
- token: '',
- //用户信息
- userInfo: {},
- //角色列表
- roles: []
- }
-
- export default state;
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;
mutationsType.js文件中定义以下常量值,代码如下:
- export const USERINFO = "USERINFO";
- export const TOKEN = "TOKEN";
- export const ROLES = "ROLES";
- export const CATEGORY_LIST = "CATEGORY_LIST";
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;
这里只仅使用了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;
在用户登录成功时,就可以获取到用户的角色信息,以及栏目列表信息。将用户信息,访问令牌,权限数据等信息存储到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组合快速搭建。
显示已进行权限过滤的栏目列表,代码如下:
- <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>
以上讲解的是通过后台动态获取所有栏目及其所对应的权限,以及动态获取用户的角色信息,进行相互匹配进行的权限显示和访问限制。以上仅供大家参考与学习。