权限在我看来指的是某个用户是否能够访问某个接口。对应到前端,即使某个用户访问了一个本不应该让他看到的页面,在访问接口时不具备权限,这样即使进入了页面,也不能看到相应的数据。但是我们前端要做的工作就是让用户在访问这个页面的时候,直接就收到提示,没有权限。
但现在许多项目中页面路由都是由前端去管理了,如何做到这一点呢,接下来我就分享一下在过往项目中我所用的方案。
我写了demo,上传到了github上,地址为:admin-permission-demo
数据库表是怎样设计的
一开始与后端去对接这个需求的时候,我是感到很懵逼的,觉得无从下手。因为我根本就不知道权限控制是怎么去做的,也不知道权限其实就是限制用户对于接口的访问。所以开始之前我觉得有必要说一下,权限表是怎样设计的。 我们项目中所使用的是 RBAC ,其实很简单,就是有这么三个东西:用户、角色、权限(资源)。图我就懒得画了,省事儿直接用一个别人画好的图。

这个权限就是项目中的接口,意思就很明显了。给角色规定了能够访问哪些接口,然后给用户分配了角色。这样就能控制用户哪些接口能访问,哪些接口不能访问。
菜单权限与按钮权限
我们项目中权限表的大概的样子:
id | p_id | type | permission | name |
---|---|---|---|---|
主键ID | 父级ID | 类型:菜单或按钮 | 权限标识 | 名称 |
权限又分为菜单权限和按钮权限,什么意思呢?
比方说我们现在要开发一个页面,叫做用户管理,在用户管理这个页面会进行一些对用户增删查改的操作。我管这个用户管理叫做菜单权限,它下面的增删查改(接口)的操作叫做按钮权限。这些接口的p_id很显然就是这个菜单权限的主键ID了。
[
{
p_id: '',
id: 1000,
name: '权限管理',
type: 1, // 菜单
permission: 'permission_manage',
children: [
{
p_id: 1000,
id: 1100,
name: '用户管理',
type: 1, // 菜单
permission: 'user_manage',
children: [
{
p_id: 110,
id: 1101,
name: '添加用户',
type: 2, // 按钮
}
...
]
}
]
}
]
怎么样,这样的数据结构是不是很熟悉,是不是就是管理系统中左侧菜单。这个 菜单权限,就是前端在做页面访问控制时所要用到的东西。这个数据结构只是我为了方便理解这样写的。 在我的项目中我向后端查询到的权限数据不长这个样子,就是一个数组,每一项是数据,没有做分组操作(就是没有children)。这样前端拿到数据了之后就可以根据 type
去整合成菜单权限集合和按钮权限集合,方便了后续的使用。
前端代码去实现权限控制
理解了权限是怎么设计的,接下来说说前端代码怎么去实现。
我过往的项目中所使用的都是 react + antd + dva + typescript。其实前端所选用的技术是什么并不重要,重要的是思路理解了,剩下的只是代码实现的不同。
首先我会要后端给我提供一个接口,查询当前用户的所有权限。然后我会把它分为 菜单权限 和 按钮权限 用 redux
去管理。
渲染左侧菜单
首先是渲染左侧菜单。在项目中一般情况下会有一个专门的左侧菜单的配置文件,在该文件里定义了菜单的名字啊、图标啊、页面路径等信息。有些菜单页面是需要被权限管理的,而有些则不需要。对于需要被权限管理的页面我会添加一个字段叫做菜单标识。
interface MenuDataItem {
name: string; // 菜单名字
icon?: string;
path: string;
children?: Array<MenuDataItem>;
permission?: string; // 菜单标识
}
const menuData: MenuDataItem[] = [...];
项目中的左侧菜单,就会根据这个 menuData
被渲染出来。这里的逻辑是首先看这个菜单有没有菜单标识,如果没有的话直接渲染。如果有菜单标识的话,就看用户是否具有这个菜单权限,有就渲染,没有就不渲染。每个项目的结构肯定不同,我就不多贴代码了,重要的是思路,具体实现我写了demo,传到了github上,感兴趣可以去看,这是地址:admin-permission-demo。
路由层面的控制
只管理了左侧菜单的渲染肯定是不够的,需要在路由层面再去做控制。一般情况下项目中会有一份路由表,react
的话路由也是组件,在路由渲染的地方去做控制就行。vue
的话是全局配置 router
的,在路由守卫中限制就行。同样的,页面对应菜单路由,看用户是否具有菜单权限,不具备就到提示权限不够页面,具备就正常显示页面。
按钮层面的控制
还是拿用户管理来举一个例子,增、删、查、改。 可能用户只具备 删、查、改的权限而不具备增的权限。这时候在页面中就不应该渲染 “添加用户” 这样的按钮了,不然用户数据输入了半天,一发请求后端一校验提示权限不足就尴尬了,我都不能做这个操作,你还展现给我干啥?
这时候去写一个组件,叫啥不重要,就比如说叫 PermissionButton
把。react的话将原本按钮作为 children 传入该组件,vue 的话应该就是 <slot>
。然后该组件还接收一个 props
,它是一个数组,就叫他 permissions
把。该数组的每一项就是按钮权限标识,代表需要哪些权限才能展示这个按钮,或者也有可能具有其中一项就可以展示。在提供一个props
去控制把,值为 every 或者 some。every就是全都有才能展示,some就是具备其中一项就能展示。
然后就是去查用户的 按钮权限 了。 具备了改组件就展示 原本组件,不具备就不展示就行了。
总结
这是我做后台管理系统所积累的一点实践把。如果大家有何更好的方案,或者觉得哪里可以改进的欢迎交流。
对 vue 的用户可能不太友好。因为demo是react实现的。但是我并不觉得这个方案在react和vue下有太大的差异。如果后面我在工作中有使用vue去做的机会,在更新一版使用vue的demo把。最重要的还是要去理解这个权限,其实也是简单的东西。希望能够帮助到有需要的人。
具体实现肯定不是几行代码能够贴清楚的,代码怎么实现也关系到具体的项目结构。
我提供了demo,上传到了github上,地址为:admin-permission-demo。
demo也是根据我自己搭的管理系统模板做的,地址为:antd-admin