<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg>
讯享网
权限控制是一个系统的核心功能,可以分为两类,一类是功能权限,一类是数据权限。今天我们说的是功能权限。
关于功能权限的控制,使用RBAC可以很好地解决,网上有大量的理论性介绍,但落地过程中,仍然有一些具体的问题,需要结合自己平台或系统的规模、面向场景选择最合适的方案,从而形成最优的设计。下面我结合自己研发平台的经验,具体说一说。
功能权限,是指系统用户能进行哪些操作,通常是菜单和按钮权限,如打开订单菜单,查询订单列表,创建新订单。对于功能权限,有标准化的解决方案,也即RBAC,通过权限项、角色、用户三张主表,以及角色-权限项对应关系表和角色-用户对应关系表两张辅助表,一共5张库表即可实现功能权限的功能,系统管理员通过系统界面即可实现灵活的权限分配和维护。
实际上RBAC只是一个统称,通常说的,都是指RBAC0,也就是上面的5张表的方案,其实还有进阶版RBAC1、RBAC2、RBAC3。
RBAC1建立在RBAC0基础之上,在角色中引入了继承的概念。比如大区经理和片区经理的关系。
RBAC2模型主要增加了责任分离关系,面向授权访问添加了诸多约束,这也是为了满足业务的需要。比如在企业内部,出纳和会计是两个不同的角色,这两个角色如果由一个人来担任,则可能会出现资金流失而无人知晓的情况,所以在RBAC模型实现时,通过授权约束,限制同一个人被授予出纳和会计这两个角色,以规避风险;
RBAC3模型是RBAC1和RBAC2的组合,既添加了角色继承,又有访问控制约束,以满足更加复杂的业务需求。
命名:角色还是用户组?
下文统一使用“用户组”来指代RBAC权限管理模型中的角色。
数据结构:单层平铺还是树形结构?
在小型应用中,用户组数量有限的情况下,单层平铺简单实用,但在大中型应用中,用户组数量成百上千个,仍采用平铺的模式则难以管理和使用。
采用树形结构后,可以方便地添加虚拟节点(如用户组分类)方便管理。
例如,新建通讯(通知)组,将一部分人放到其下,可以供消息模块(短信、邮件、电话)等使用。
此外,在流程审批中,同样存在一部分流程中的环节处理人员,往往也是某些特定用户集合,,创建一个名为“流程岗位”的用户组,将这类数据放进去更合适。

换个角度想,传统意义上用于功能权限控制的角色,更适合作为用户组的一个分支。
是否权限继承?
用户组的数据结构采用树形后,面临一个新的问题,即是否要考虑权限继承问题。
例如,给某一用户组分配的某一权限,则其上级用户组也自动拥有了其权限,也就是通常意义上的员工有的权限,领导也自动有了,这实际是RBAC1模型要解决的问题。
这么做看上去会减轻权限初始化工作以及权限维护工作量,但实际上结果可能是相反的,增加权限维护的复杂性,并且某些业务功能并不适配这种模式。举例说明,某个基层工作人员使用的功能,如班组作业,需要获取当前班组编码等数据,如果给部门经理也分配了该功能菜单的权限,则会因为取不到其所属的班组编码数据而引发无法正常显示或使用。
上面这个例子,实际深入思考下,并不是权限继承机制的问题。而是使用这种机制,需要从全局好好规划用户组,明确哪些用户组是继承关系。班组成员和部门经理是上下级关系,但是从用户组继承角度而言,并不应该存在继承关系。
存在继承关系的角色,应该是类似部门管理员-》公司管理员-》集团管理员这种模式。
引入权限继承,会增加系统设计、实现、运维的复杂性,因此,不考虑权限继承问题,树形结构仅用于用户组的分类与管理。
用户组规划
按照上述用户组的分类考虑,规划如下:
1.角色:传统意义上的岗位和职务,如部门经理、固定资产接口人,其下可以进一步分公共角色和专用角色,公共角色全局公用,如部门经理、固定资产接口人,每个部门都有该角色;专用角色往往是特定部门特定岗位才有的,如采样人员、巡检人员,可以在用户组下建组织机构虚拟节点,将这些专用角色挂靠在下面,更方便管理(使用角色时,不会显示在公共角色下,从而避免展示的总数量过多而影响选择)。
2.通讯组:预置的消息通知用户集合,可供消息模块(短信、邮件、电话)等使用,在某些业务事件发生时,如发生火灾,系统自动发送应急短信给通讯组用户。
3.流程岗位:工作流流程审批专用,如合同审查人员,会签人员,往往是为某条或某几条流程设置的人员集合,与管理上的岗位和职务没有很强的关联性,也不适合在常规功能权限分配是显示出来。
……
控制方案
权限控制有很多现成的功能组件可用,如Apache Shiro,Spring Security,如果系统自身比较小,自己基于五张表实现一个也不难。
这里重点说下,后端收到前端请求,如何来判断当前用户是否有权限的处理方案。这个地方走过弯路,开始想基于路径,后来发现问题较多,实用性差,变更为基于编码的方式,下面具体说说。
基于路径的自动匹配
权限项最初的方案是基于rest理念,权限配置无侵入,即在权限项管理中配置请求的路径,当收到前端请求时,由SpringMVC框架映射到具体某个方法上,在这个方法执行前验证请求路径是否与权限项中配置的路径匹配,但这种方式存在一个问题,即通配符引发的匹配问题。
例如/system/user/* 的get请求,通常是获取某个具体用户的信息,但这种路径,会与一些其他方法冲突,例如分页方法的路径为/system/user/page,这两个请求从前端发起,SpringMvc框架能区分开应该映射到哪个方法,但是在进行权限验证时,这两个路径实际都能映射到/system/user/*上,也就是说,如分配了查看用户权限,也相当于给分页方法分配了权限。
此外,实际并不希望权限的颗粒度那么细,具体到每一个方法,否则会给权限维护带来麻烦。实际往往希望将一系列相关的操作打包成1个权限项,例如一旦给用户分配了用户查询权限,获取用户列表list和分页查询page方法都有权限调用,不需要另行配置。

上面提到的两个问题,一是技术层面,通配符引发的匹配不准确问题,这个问题理论上能解决掉;二是设计与使用过程中,不希望将权限的颗粒度划分的过细,具体到每个请求,这一点实际也可以配一个权限项,对应多个请求路径来解决,因此无侵入的控制方式应该能实现的。
但这种方式,在权限验证环节可能存在性能问题,即收到请求后,基于路径匹配去验证当前用户是否有权限,要将该用户对应的用户组,拥有的权限项对应的所有路径规则去做遍历匹配。
同时,新开发的功能,得注意及时配置权限项进行控制;并且与已经配置的路径规则不要冲突,否则容易引发权限范围放大或缩小,配置起来也比较痛苦,容易出错。
基于编码的预置控制
如上,为解决基于路径方法权限判断的问题,以及权限项打包授权问题,采用了权限编码的方式,一方面,在权限项维护时添加权限编码,然后在后端方法上添加注解,明确该方法受哪个权限编码控制,在前端按钮上也通过该权限编码来控制其可见性。
这种方式解决上基于路径的两个直接问题,以及进行权限判断时的间接性能问题。
但在权限编码变更时,需要开发人员同步调整前端和后端。
权限编码一般情况下也不会变,但若出现业务需求,调整菜单路径,则会引发问题。
若要解决该问题,除非将依据调整为权限项的标识,即无任何业务含义,这种方案虽然可以任意调整菜单层级,但可读性极差,在开发和维护阶段很容易出错,整体评估下来,还不如采取有业务含义的编码更清晰和易于维护。上面提到的调整菜单问题,开发人员进行同步调整即可,工作量较小,不是什么大问题。
平台名称:一二三开发平台
简介: 企业级通用开发平台
设计资料:[csdn专栏]
开源地址:[Gitee]
开源协议:MIT
如果您在阅读本文时获得了帮助或受到了启发,希望您能够喜欢并收藏这篇文章,为它点赞~
请在评论区与我分享您的想法和心得,一起交流学习,不断进步,遇见更加优秀的自己!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/176688.html