用户角色权限设计

在多角色的系统中(比如管理端)一般会给不同角色的用户分配不同的权限。权限一般有以下分类:

1
2
3
4
* 页面权限
* 操作权限
* 数据权限
* API 权限

页面一般通过路由分发,所以页面权限也叫做路由权限。在这些权限中,API 权限是后端权限,其他都是前端权限,下面从前端角度介绍用户角色权限的设计。

权限配置

页面权限包含了所有权限类型,操作和数据都在页面内,操作权限和数据权限可作为页面权限的子权限。页面绝大多数由菜单触发(少数由按钮或地址栏输入触发),以菜单为载体不但能配置菜单本身,还能配置权限。

权限既可以在服务端配置,也可以在客户端配置,在服务端配置更容易维护。

  • 服务端配置
1
2
3
4
5
6
7
8
9
10
{
id: '', // ID
parentId: '', // 父级菜单 ID
title: '', // 菜单名称(菜单管理列表的显示名称)
path: '', // 路由或 URL
sort: 0, // 排序
icon: '', // 图标
hidden: '', // 是否隐藏,不生成菜单
functions: '' // 操作权限(增、删、改、查...)
}

菜单权限列表是一个树形结构,描述了菜单的从属关系,决定了菜单的生成层级。对于那些不需要生成菜单的页面(由按钮触发或地址直接打开的页面),可通过 hidden 字段描述菜单项是否显示。

实际操作中,一般由菜单管理生成总的菜单权限列表,角色管理时为角色勾选权限,然后在用户管理中为用户赋予角色。

  • 客户端配置

以在前端路由表中配置为例(当然不一定写在路由表中,独立一个菜单权限文件也可以):

1
2
3
4
5
6
7
8
9
{
meta : {
hidden: false // 是否生成菜单
roles: ['admin', 'teacher'], // 空表示不需要权限,任何角色都可访问,即为开放菜单
functions: {
admin: ['add', 'delete', 'edit', 'export']
}
}
}

鉴权

  • 路由鉴权

页面权限采用白名单制,不在此名单内的访问和操作都是非法的,实际需求中并不是所有的页面都需要权限,比如 404,登录页,活动页等,这些页面都不需要权限。

1
2
3
4
5
6
7
8
9
10
// 鉴权列表外的,直接放行
if (!totalRoutePermitList.includes(curRouteName)) {
// 有权限
} else {
if (myRoutePermitList.includes(curRouteName)) {
// 有权限
} else {
// 无权限
}
}

或者将这些不需鉴权页面作为访问白名单加入到我的权限列表进行鉴权,但这需要维护白名单。

1
2
3
4
5
6
7
// 将白名单列表合并到我的权限列表
myRoutePermitList = [...routePermitWhiteList, ...myRoutePermitList]
if (myRoutePermitList.includes(curRouteName)) {
// 有权限
} else {
// 无权限
}
  • 操作鉴权

不是所有的操作都需要参与鉴权,根据需求选择性鉴权即可。

1
2
3
if (!myFunPermitList.includes(curFunName)) {
// 无权限
}

在 Vue 中通常配合 v-if 或自定义指令实现操作按钮的隐藏显示。