近年来,随着react、angular、vue等前端框架的兴起,前后端分离的架构迅速流行起来。 但与此同时,权限控制也带来了问题。
网上很多前后端分离的权限只是描述了前端的权限控制,都是比较简单固定的角色场景,不能满足我们用户和角色都是动态的场景。
而只有前端的权限控制并不是真正的权限控制,只是减少页面结构暴露,提升用户体验的作用。
场景
本系统为后台管理系统,包括用户创建、用户登录、用户对自身资源的管理。 用户经常添加和删除用户,也可以根据工作情况随时调整页面和功能权限,所以采用用户-角色-页面权限方案。
为什么不行:根据前端路由表,显示左侧菜单,但是vue-router的路由表主要是组织代码,往往我们需要的菜单并不一致。 比如一个前端路由a有子路由b和c,但是在菜单中我们想直接把b和c显示在一级菜单或者把b和c放在其他菜单下。 所以这是非常不灵活的。 路由是菜单还是页面? 是否需要在菜单中显示? 您要验证权限吗? 哪个角色或用户有权限? 这些都需要写入到前端路由中用户 角色 权限设计,一旦有什么权限变化,代码就需要调整很多。 如果权限是在前端硬编码的,那么角色或用户必须是已知的和固定的。 例如,页面 1 的元添加属性以将可访问角色标识为 a 和 b
页
一个页面就是一个前端页面,比如首页、用户管理页面、资源管理页面等。
基本思路是:前端路由不变,数据库存储菜单结构、页面权限控制(可以直接做成页面方便管理)等,前端根据数据库中的菜单结构和权限信息,只显示其有权限的菜单,在路由守卫中进行权限控制,防止未经授权手动输入路径打开页面。
前端路由(vue-router)需要正常创建页面和路由。 数据库存储菜单结构和页面权限信息。 菜单(目录,非内容页)可以自己创建,前端路由中不需要有,因为这意味着菜单的可视化组织结构页(内容页)必须存在于前端路由。 页面,因为这是用户需要访问的内容。 菜单和页面形成上下关系。 第一层可以是菜单也可以是内容页,内容页也可以放在菜单下面。 这样理论上(需要页面菜单样式的支持)可以形成一个无限的菜单菜单,页面的基本属性包括title(对应路由标题)、name(对应路由名称)、path(对应route path), parent, type(menu/page), 是否可见(是否显示左侧菜单栏:部分页面可能是页面中的链接),是否需要验证权限(部分页面如首页做不需要验证,所有人都可以进入)不需要控制权限,不需要显示左侧菜单的路径。 这里可以不管理,比如404页面等,前台打开后,可以得到数据库中的所有信息菜单,页面,结构根据是否登录用户 角色 权限设计,是否需要认证权限进行控制,或无权限跳转到登录页面。 用户登录成功后,获取该用户对应的页面权限列表,使用上一步获取的所有页面和结构。 渲染用户拥有的权限列表的菜单,只包含用户拥有权限的菜单,完善用户健康检查,避免显示大量用户无法访问的菜单,影响使用和不必要的功能暴露。在路由中guard,每次跳转都根据上一步得到的权限列表进行判断。 如果没有权限,可以返回404或者没有权限的页面,防止用户手动输入路径进行未经授权的访问。
页面管理:
特征
某些功能需要单独控制权限。 例如,用户管理页面可能允许多个角色查看,但“创建用户”功能只允许某个角色使用,因此仅使用页面权限是不够的。 因此需要细粒度的功能权限控制。
网上的解决方案都说:基于资源控制增删改查,比如用户的创建、修改、删除、查询。 但是,在我的实际使用中,发现并不实用。 至少像我这样的管理背景,资源不是简单的增删改查。 其他地方可能还有其他操作也会影响到这个用户资源,比如禁用删除一个角色也需要禁用删除一个用户,那么这个权限是属于角色的还是属于用户的,或者后台是否发生了变化,角色影响其他资源或不再对用户进行操作,都会影响权限控制。
因此,更合理的做法应该是对每个功能进行单独控制,并与页面关联起来,而不局限于增删改查。 可以任意定制,只需要和前后端开发商定一个唯一标识即可。
上面的例子中像素游戏素材,在用户管理页面下有各种用户功能,在角色管理页面中还有一个角色禁用和删除功能,可以分别定义为role_disable和role_delete。 如果你有role_delete权限,即使你没有user_delete权限也可以。 直接删除用户,否则不要赋予role_delete权限。
用户登录后,从数据库中获取其拥有的权限列表,保存在vuex中,包括页面和功能的对应关系。 比如页面名称为user:{user:['user_delete', 'user_query']},页面删除根据按钮可以通过v-if="hasPermission('user_delete')"来判断. 页面功能管理:
获取用户拥有的权限:
角色
角色类似于身份或职位,每个角色都有自己的权限范围。 一个角色可以有多个页面权限。 一个角色可以有多个功能权限。
角色管理:
角色分配权限:
用户
可以创建和删除用户,一个用户可以随时改变自己的工作内容,或者承担多个角色,因此可以为他分配一个或多个角色,他所拥有的角色的权限就是他的权限。 至此,就可以打通权限前端的权限分配,用户-角色-页面权限,功能权限。
用户管理:
用户分配的角色:
前端效果
前端页面菜单效果:
后端权限
在传统的前后端不分离的情况下,路由由后端统一管理。 简单的方法比如用户管理页面/user/,那么里面用到的接口都是使用相同的前缀比如/user/add,/user/delete等,那么只要判断用户有/user/权限可以访问/user/*的所有接口。
前后端分离后面临的问题:
界面
解决方法:需要控制权限的接口上传管理(可以做成管理页面)。 每个页面和功能都可以与多个界面相关联。 比如用户页面关联用户查询接口和用户编辑接口,用户删除功能关联用户删除接口后台判断请求的路径,user->role->page/function->接口,有接口权限可以访问前后端开发团队3D动画,不容易一一比较,而且前端有自己的路由(这个路由受限于代码组织结构),等等,同一个接口用传统的方式不容易处理,可能会被多个前端页面多次使用