每个系统项目中,都离不开权限的管理。有些小项目为了快速开发,可能会省略权限的处理;但中大型项目无法回避,中大型系统使用的人员比较繁杂,每个人身处不同职位或职权,所看到信息是不一样的。
权限管理,一般是先建“角色”,给角色添加某些栏目显示权限,或赋予增删改权限,再将“角色”指派给对应用户。一个用户可能只有一个角色,或多个角色,这样该用户则拥有了这些“角色”的权限集合。
下面我们通过代码,来处理栏目显示的权限,来了解前端是否何处理权限问题的。
前面几篇已介绍了如何使用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状态管理器中代码如下:
以上登录页面只展示了业务部分代码,dom部分大家可以使用element-ui组合快速搭建。
显示已进行权限过滤的栏目列表,代码如下:
{{item.name}}
以上讲解的是通过后台动态获取所有栏目及其所对应的权限,以及动态获取用户的角色信息,进行相互匹配进行的权限显示和访问限制。以上仅供大家参考与学习。