【认证授权】权限系统设计详解
- 1.权限系统设计概述
- 2.主流权限模型概述
- 3.RBAC 的深度拓展
- 4.RBAC 权限管理的在实际系统中的应用
- 5.企业案例:转转新权限系统设计
- 6.转转新权限系统设计:后端技术案例
- 7.转转新权限系统设计:前端技术案例
1.权限系统设计概述
权限管控可以通俗地理解为权力限制,即不同的人由于拥有不同权力,他所看到的、能使用的可能不一样。对应到一个应用系统,其实就是一个用户可能拥有不同的数据权限(看到的)和操作权限(使用的)。
主流的权限模型主要分为以下五种:
- ACL 模型:访问控制列表
- DAC 模型:自主访问控制
- MAC 模型:强制访问控制
- ABAC 模型:基于属性的访问控制
- RBAC 模型:基于角色的权限访问控制
2.主流权限模型概述
ACL 模型:访问控制列表
ACL 是最早的、最基本的一种访问控制机制,是基于客体进行控制的模型,在其他模型中也有 ACL 的身影。为了解决相同权限的用户挨个配置的问题,后来也采用了用户组的方式
原理:每一个客体都有一个列表,列表中记录的是哪些主体可以对这个客体做哪些行为,非常简单。
例如:当用户 A 要对一篇文章进行编辑时,ACL 会先检查一下文章编辑功能的控制列表中有没有用户 A,有就可以编辑,无则不能编辑。再例如:不同等级的会员在产品中可使用的功能范围不同。
缺点:当主体的数量较多时,配置和维护工作就会成本大、易出错。
DAC 模型:自主访问控制
DAC 是 ACL 的一种拓展
原理:在 ACL 模型的基础上,允许主体可以将自己拥有的权限自主地授予其他主体,所以权限可以任意传递。
例如:常见于文件系统,LINUX,UNIX、WindowsNT 版本的操作系统都提供 DAC 的支持。
缺点:对权限控制比较分散,例如无法简单地将一组文件设置统一的权限开放给指定的一群用户。主体的权限太大,无意间就可能泄露信息。
MAC 模型:强制访问控制
MAC 模型中主要的是双向验证机制。常见于机密机构或者其他等级观念强烈的行业,如军用和市政安全领域的软件
原理:主体有一个权限标识,客体也有一个权限标识,而主体能否对该客体进行操作取决于双方的权限标识的关系。
例如:将军分为上将>中将>少将,军事文件保密等级分为绝密>机密>秘密,规定不同军衔仅能访问不同保密等级的文件,如少将只能访问秘密文件;当某一账号访问某一文件时,系统会验证账号的军衔,也验证文件的保密等级,当军衔和保密等级相对应时才可以访问。
缺点:控制太严格,实现工作量大,缺乏灵活性。
RBAC:基于角色的权限访问控制
在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。
RBAC 三要素:
- 用户:系统中所有的账户
- 角色:一系列权限的集合(如:管理员,开发者,审计管理员等)
- 权限:菜单,按钮,数据的增删改查等详细权限。
角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。
角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系同样也存在继承关系防止越权。
优点:便于角色划分,更灵活的授权管理;最小颗粒度授权
以一个简单的场景(Gitlab 的权限系统)为例,用户系统中有 Admin、Maintainer、Operator 三种角色,这三种角色分别具备不同的权限,比如只有 Admin 具备创建代码仓库、删除代码仓库的权限,其他的角色都不具备。我们授予某个用户 Admin 这个角色,他就具备了 创建代码仓库 和 删除代码仓库 这两个权限。
ABAC 模型:基于属性的访问控制
是一种比 RBAC模型 更加灵活的授权模型,它的原理是通过各种属性来动态判断一个操作是否可以被允许。这个模型在云系统中使用的比较多,比如 AWS,阿里云等
原理:在 ABAC模型 中,一个操作是否被允许是基于对象、资源、操作和环境信息共同动态计算决定的。
通常有四类:
- 对象:对象是当前请求访问资源的用户。用户的属性包括 ID,个人资源,角色,部门和组织成员身份等
- 资源:资源是当前用户要访问的资产或对象,例如文件,数据,服务器,甚至 API
- 操作:操作是用户试图对资源进行的操作。常见的操作包括“读取”,“写入”,“编辑”,“复制”和“删除”
- 环境:环境是每个访问请求的上下文。环境属性包含访问的时间和位置,对象的设备,通信协议和加密强度等
在 ABAC模型 的决策语句的执行过程中,决策引擎会根据定义好的决策语句,结合对象、资源、操作、环境等因素动态计算出决策结果。每当发生访问请求时,ABAC模型 决策系统都会分析属性值是否与已建立的策略匹配。如果有匹配的策略,访问请求就会被通过。
例如:
考虑下面这些场景的权限控制:
- 授权某个人具体某本书的编辑权限
- 当一个文档的所属部门跟用户的部门相同时,用户可以访问这个文档
- 当用户是一个文档的拥有者并且文档的状态是草稿,用户可以编辑这个文档
- 早上九点前禁止 A 部门的人访问 B 系统
- 在除了上海以外的地方禁止以管理员身份访问 A 系统
- 用户对 2022-06-07 之前创建的订单有操作权限
可以发现上述的场景通过 RBAC模型 很难去实现,因为 RBAC模型 仅仅描述了用户可以做什么操作,但是操作的条件,以及操作的数据,RBAC模型 本身是没有这些限制的。但这恰恰是 ABAC模型 的长处
缺点:规则复杂,不易看出主体与客体之间的关系,实现非常难,现在应用得很少。
3.RBAC 的深度拓展
RBAC 模型可以分为:RBAC0、RBAC1、RBAC2、RBAC3 四个阶段,一般公司使用 RBAC0 的模型就可以。另外,RBAC0 相当于底层逻辑,后三者都是在 RBAC0 模型上的拔高
1、RBAC0 模型
用户和角色、角色和权限多对多关系。简单来说就是一个用户拥有多个角色,一个角色可以被多个用户拥有
2、RBAC1 模型
相对于 RBAC0 模型,增加了角色分级的逻辑,类似于树形结构,下一节点继承上一节点的所有权限,如 role1 根节点下有 role1.1 和 role1.2 两个子节点
角色分级的逻辑可以有效的规范角色创建(主要得益于权限继承逻辑),例如 BD 之间就有分级(经理、主管、专员),如果采用 RBAC0 模型做权限系统,可能需要为经理、主管、专员分别创建一个角色(角色之间权限无继承性),极有可能出现一个问题,由于权限配置错误,主管拥有经理都没有的权限。
而 RBAC1 模型就很好解决了这个问题,创建完经理角色并配置好权限后,主管角色的权限继承经理角色的权限,并且支持针对性删减主管权限。
3、RBAC2 模型
基于 RBAC0 模型,对角色增加了更多约束条件。
如角色互斥,比较经典的案例是财务系统中出纳不得兼管稽核,那么在赋予财务系统操作人员角色时,同一个操作员不能同时拥有出纳和稽核两个角色。
RBAC2 模型主要是为了增加角色赋予的限制条件,这也符合权限系统的目标:权责明确,系统使用安全、保密。
4、RBAC3 模型
同样是基于 RBAC0 模型,但是综合了 RBAC1 和 RBAC2 的所有特点
4.RBAC 权限管理的在实际系统中的应用
RBAC 权限模型由三大部分构成,即用户管理、角色管理、权限管理。
用户管理按照企业架构或业务线架构来划分,这些结构本身比较清晰,扩展性和可读性都非常好。
角色管理一定要在深入理解业务逻辑后再来设计,一般使用各部门真实的角色作为基础,再根据业务逻辑进行扩展。
权限管理是前两种管理的再加固,做太细容易太碎片,做太粗又不够安全,这里我们需要根据经验和实际情况来设计。
1、用户管理
用户管理中的用户,是企业里每一位员工,他们本身就有自己的组织架构,我们可以直接使用企业部门架构或者业务线架构来作为线索,构建用户管理系统
实际业务中的组织架构可能与企业部门架构、业务线架构不同,需要考虑数据共享机制,一般的做法为授权某个人、某个角色组共享某个组织层级的某个对象组数据
2、角色管理
一般角色相对于用户来说是固定不变的,每个角色都有自己明确的权限和限制,这些权限在系统设计之处就确定了,之后也轻易不会再变动。
角色管理注意:
a. 自动获得基础角色:当员工入职到某部门时,该名员工的账号应该自动被加入该部门对应的基础角色中,并拥有对应的基础权限。这种操作是为了保证系统安全的前提下,减少了管理员大量手动操作。使新入职员工能快速使用系统,提高工作效率
b. 临时角色与失效时间:公司业务有时需要外援来支持,他们并不属于公司员工,也只是在某个时段在公司做支持。此时我们需要设置临时角色,来应对这种可能跨多部门协作的临时员工。
如果公司安全级别较高,此类账号默认有固定失效时间,到达失效时间需再次审核才能重新开启。避免临时账号因为流程不完善,遗忘在系统中,引起安全隐患。
c. 虚拟角色:部门角色中的等级,可以授权同等级的员工拥有相同的权限,但某些员工因工作原因,需要调用角色等级之外的权限,相同等级不同员工需要使用的权限还不相同。
这种超出角色等级又合理的权限授予,我们可以设置虚拟角色。这一虚拟角色可集成这一工作所需的所有权限,然后将它赋予具体的员工即可。这样即不用调整组织架构和对应的角色,也可以满足工作中特殊情况的权限需求。
d. 黑白名单:
白名单:某些用户自身不拥有某部门的顶级角色,但处于业务需求,需要给他角色外的高级权限,那么我们可以设计限制范围的白名单,将需要的用户添加进去即可。
在安全流程中,我们仅需要对白名单设计安全流程,即可审核在白名单中的特殊用户,做到监控拥有特殊权限的用户,减少安全隐患。
黑名单:比较常见的黑名单场景是某些犯了错误的员工,虽然在职,但已经不能给他们任何公司权限了。这种既不能取消角色关联,也不能完全停用账号的情况,可以设置黑名单,让此类用户可以登录账号,查看基本信息,但大多数关键权限已经被黑名单限制。
3、权限管理
权限管理一般从三个方面来做限制。页面/菜单权限,操作权限,数据权限。
a. 页面/菜单权限
对于没有权限操作的用户,直接隐藏对应的页面入口或菜单选项。这种方法简单快捷直接,对于一些安全不太敏感的权限,使用这种方式非常高效。
b. 操作权限
操作权限通常是指对同一组数据,不同的用户是否可以增删改查。对某些用户来说是只读浏览数据,对某些用户来说是可编辑的数据。
c. 数据权限
对于安全需求高的权限管理,仅从前端限制隐藏菜单,隐藏编辑按钮是不够的,还需要在数接口上做限制。如果用户试图通过非法手段编辑不属于自己权限下的数据,服务器端会识别、记录并限制访问。
4、用户管理系统权限设计中的更多实践细节
a. 超级管理员
超级管理员是用来启动系统,配置系统的账号。这个账号应该在配置好系统,创建管理员之后被隐藏起来。超级管理员账号拥有系统中全部权限,可穿梭查看各部门数据,如果使用不恰当,是系统管理的安全隐患。
b. 互斥角色如何处理
当用户已经有用的角色和即将添加的角色互相互斥时,应该在添加新角色时,提示管理员因角色互斥的原因,无法进行新角色添加。如需添加,要先撤销掉前一个角色,再添加新角色。
c. 用户管理权限系统设计一定要简单清晰
在设计权限系统之处,一定要理清思路,一切从简,能不增加的多余角色和权限逻辑,就一定不要增加。因为随着公司业务的扩大,权限和角色也会随之增多,如果初期设计思路不严谨,那么权限系统会随着业务的扩大而无限混乱下去,此时再来整理权限,已经太晚了。所以初期设计就一定要条理清晰,简单明了,能避免后续非常多不必要的麻烦。
5.企业案例:转转新权限系统设计
基本思想
标准的 RBAC模型 是完全遵守 用户 -> 角色 -> 权限
这个链路的,也就是用户的权限完全由他所拥有的角色来控制,但是这样会有一个缺点,就是给用户加权限必须新增一个角色,导致实际操作起来效率比较低。所以转转在 RBAC模型 的基础上,新增了给用户直接增加权限的能力,也就是说既可以给用户添加角色,也可以给用户直接添加权限。最终用户的权限是由拥有的角色和权限点组合而成。
新权限系统的权限模型:用户最终权限 = 用户拥有的角色带来的权限 + 用户独立配置的权限,两者取并集。
基础三步:
- 首先,将集团所有的用户(包括外部用户),通过 统一登录与注册 功能实现了统一管理,同时与公司的组织架构信息模块打通,实现了同一个人员在所有系统中信息的一致,这也为后续基于组织架构进行权限管理提供了可行性。
- 其次,因为新权限系统需要服务集团所有业务,所以需要支持多系统权限管理。用户进行权限管理前,需要先选择相应的系统,然后配置该系统的 菜单权限 和 数据权限 信息,建立好系统的各个权限点。
- 最后,创建该系统下的不同角色,给不同角色配置好权限点。比如店长角色,拥有店员操作权限、本店数据查看权限等,配置好这个角色后,后续只需要给店长增加这个角色,就可以让他拥有对应的权限。
完成上述配置后,就可以进行用户的权限管理了。有两种方式可以给用户加权限:
- 先选用户,然后添加权限。该方式可以给用户添加任意角色或是菜单/数据权限点。
- 先选择角色,然后关联用户。该方式只可给用户添加角色,不能单独添加菜单/数据权限点。
权限系统自身的权限管理
对于权限系统来说,首先需要设计好系统自身的权限管理,也就是需要管理好 ”谁可以进入权限系统,谁可以管理其他系统的权限“,对于权限系统自身的用户,会分为三类:
- 超级管理员:拥有权限系统的全部操作权限,可以进行系统自身的任何操作,也可以管理接入权限的应用系统的管理操作。
- 权限操作用户:拥有至少一个已接入的应用系统的超级管理员角色的用户。该用户能进行的操作限定在所拥有的应用系统权限范围内。权限操作用户是一种身份,无需分配,而是根据规则自动获得的。
- 普通用户:普通用户也可以认为是一种身份,除去上述 2 类人,其余的都为普通用户。他们只能申请接入系统以及访问权限申请页面。
权限类型的定义
新权限系统中,把权限分为两大类,分别是:
- 菜单功能权限:包括系统的目录导航、菜单的访问权限,以及按钮和 API 操作的权限
- 数据权限:包括定义数据的查询范围权限,在不同系统中,通常叫做 “组织”、”站点“等,在新权限系统中,统一称作 ”组织“ 来管理数据权限
默认角色的分类
每个系统中设计了三个默认角色,用来满足基本的权限管理需求,分别如下:
- 超级管理员:该角色拥有该系统的全部权限,可以修改系统的角色权限等配置,可以给其他用户授权。
- 系统管理员:该角色拥有给其他用户授权以及修改系统的角色权限等配置能力,但角色本身不具有任何权限。
- 授权管理员:该角色拥有给其他用户授权的能力。但是授权的范围不超出自己所拥有的权限。
举个栗子:授权管理员 A 可以给 B 用户添加权限,但添加的范围 小于等于 A 用户已拥有的权限。
经过这么区分,把 拥有权限 和 拥有授权能力 ,这两部分给分隔开来,可以满足所有的权限控制的场景。
操作日志
系统操作日志会分为两大类:
- 操作流水日志:用户可看、可查的关键操作日志
- 服务 Log 日志:系统服务运行过程中产生的 Log 日志,其中,服务 Log 日志信息量大于操作流水日志,但是不方便搜索查看。所以权限系统需要提供操作流水日志功能。
在新权限系统中,用户所有的操作可以分为三类,分别为新增、更新、删除。所有的模块也可枚举,例如用户管理、角色管理、菜单管理等。明确这些信息后,那么一条日志就可以抽象为:什么人(Who)在什么时间(When)对哪些人(Target)的哪些模块做了哪些操作。
这样把所有的记录都入库,就可以方便的进行日志的查看和筛选了。
6.转转新权限系统设计:后端技术案例
权限系统框架
权限系统主要解决两个问题:
- 前端渲染:接入系统用户登录后,获取自己有权限的菜单,也就是前端sdk请求权限系统获取有权限的菜单并进行自动渲染。
- 后端鉴权:用户请求接入系统后端,拒绝没有权限的接口访问,防止无权限用户获取后端接口地址后直接访问无权限的接口。
为了解决这两个问题,必然需要引入一些配套内容,其中重要的功能点如下:
- 用户管理:统一登录系统,支撑权限系统识别登录用户。
- 权限管理:系统管理、角色管理、菜单管理、数据管理、角色人员绑定等功能,方便为用户绑定相应的权限。
- 后端鉴权:访问接入系统接口调用时使用。
用户管理
统一登录利用浏览器携带Cookie特点:不同二级域名可以携带一级域名的Cookie。统一登录系统为接入系统种植一级域名Cookie,例如OA系统oa.zhuanspirit.com、权限系统自身id.zhuanspirit.com统一种植域名为*.zhuanspirit.com的Cookie,这样OA、权限系统等接入统一登录系统的系统就可以做到一处登录处处访问
ngix会对*.zhuanspirit.com域名的请求做Cookie合法校验,校验不通过跳转到登录页,同时携带原url信息。校验合法性是通过Cookie<sso_uid,sso_code>
的值是否和Redis中一致,不一致就需要重新登录。
后端鉴权
后端鉴权sdk通过切面编程的思想,对请求url或者code进行拦截鉴权,如果登录用户没有权限,则返回错误:
核心方法:
AuthResult res = authentication.check(new AppCodeAuthParmBuilder(APP_CODE, CODE, request));
- APP_CODE:系统的系统编号
- CODE:权限编码(可为空,为空时根据url鉴权)
- request:HttpServletRequest(从中获取Cookie信息解析出登录用户,以及url信息判断用户是否有此url权限)
使用demo:
利用Spring Interceptor切面技术,下面是架构管理平台关于ZZLock后台操作的一个例子:
@Component
public class ZZLockInterceptor implements HandlerInterceptor {
@Resource
private Authentication authentication;
private static final String APP_CODE = "arch_ipms";
private static final String CODE = "ro_zzlock";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
AuthResult res = authentication.check(new AppCodeAuthParmBuilder(APP_CODE, CODE, request));
if (res.isSuccess() && res.getCode() == ResultCodeEnum.SUCCESS.getCode()) {
return true;
} else {
UserDTO user = authentication.parseUser(request);
logger.info("菜单 zzlock_get user {} 鉴权结果 code {} msg {}", user.getLoginName(), res.getCode(), res.getMsg());
response.getWriter().write("user: " + user.getLoginName() + " no auth");
response.getWriter().close();
}
return false;
}
}
7.转转新权限系统设计:前端技术案例
权限前端 SDK 设计
目前 sdk 提供以下接口,利用login
和getUserPermssion
获取用户信息和权限数据,并保存在全局变量中,并提供一个特殊接口routerFilter
可利用实现对菜单树状数据进行权限过滤