平台化服务的基石(四):再议用户权限,更优雅的模型
在《用户认证模型设计》、《权限模型设计》、《隔离与交互策略模型》中笔者介绍了用户权限的演进,逐步形成了相对完善的模型体系,但在文末也遗留了些改进思考。本文将延续之前的演进以改进点为切入聊一下更优雅的模型。
改进思考回顾及补充
资源(Resource)加上资源操作(Operation)用于定位一个操作,但这一模型下“资源”并不纯粹,比如有 HTTP API“GET /user/{userId}”及“GET /mgr/user/{userId}”,两个 API 对应的角色不同,但它们对应的都是用户资源,目前的资源模型需要 2 条记录,怎么更优雅地实现?
账号认证配置(AccountIdentConfig)中配置了 OAuth 的 AK/SK 信息以存放微信公众号的 AppId/AppSecret,这看似合理,但有没有更统一、简单的模型?
共享应用章节介绍的模型有个缺陷:无法实现不同应用的自定义授权。如商城应用和在线投保应用去申请消息中心应用的权限,给到的权限是对等的,无论实现消息中心模块 1 的权限给商城应用、模块 2、3 的权限给在线投保应用,但这种场景却又是存在的
本次涉及的权限模型包含了 RBAC、ACL,在统一资源定位章节又涉及了部分 ABAC,有没有简单、优雅的方案实现 ABAC 权限模型?
针对上述问题,演化出了统一资源模型
及简化版ABAC权限模型
。
统一资源模型
此模型将一切可操作的元素都视为“资源”,包含但不限于:API、菜单、页面元素、关系型数据库/表/行/字段、Redis 缓存 key、OAuth 服务等。可以简单地将资源看作多树结构,每棵树的树根为资源主体(ResourceSubject),它包含了该树所有节点的公共信息,每个节点为资源(Resource)。
比如资源主体(ResourceSubject):
如上所示,我们可以定义不同的资源主体类型(Kind),每个资源主体都有对应的 URI、要访问该资源的通用认证信息(AK/SK)及特殊信息(比如像华为的视频点播服务需要使用平台账号名),同时每个资源主体也有对应的所属应用 Id 及租户 Id。
资源主体的 URI 用于定位资源,一般可直接寻址找到资源,但也有需要二次处理的情况,比如 MENU、ELEMENT、OAUTH 这几个都应该路由到用户权限系统,由用户权限系统来理解 URI 并操作对应的资源。
资源主体编码可以由<所属应用Id>.<资源类型名称>.<自定义编码>
组成,如2.reldb.main
表示应用 2 的主数据库,2.reldb.read
表示应用 2 的只读库。
接下来我们看一下资源(Resource):
资源的 URI 是对外暴露的资源地址,由<资源主体编码>+<资源路径组成>+<资源查询条件>
组成,资源路径支持 ant 表达式,资源查询条件可以精确到资源属性级与记录级的定位。
资源开放等级类型名称(expose_kind)用于确定该资源的作用域,默认是应用级(APP),即只有该应用(rel_app_id)可以使用,也可以是租户级(TENANT)表示只有该租户(rel_tenant_id)下的应用可以使用、全局(GLOBAL)表示所有应用都可以使用。如上示例中的应用控制台,从功能上看这个控制台要支持所有应用登录后操作自己应用相关的数据,所以这个资源由用户权限这个应用提供(rel_app_id = <用户权限中心的应用 Id>),但它的开放等级为 GLOBAL,这样所有的应用都可以访问到对应的 API。
触发后的操作(action)一般用于点击某个菜单或元素后打开一个链接,该链接多为前端的路由地址。
通过上述两张简单的表我们可以很容易实现一个可扩展的、统一的资源模型。
简化版 ABAC 权限模型
以笔者的经验看主流的 RBAC 模型及其扩展模型在一般的互联网场景中可以比较好的支撑,但在传统企业、产业互联网企业中往往存在着复杂的组织架构关系及特殊的权限要求,仅以角色为出口关联用户与权限的方式就显得过于简陋了。所以我们会去考虑 ABAC 模型,后者有很多的好处,引用 AWS 相关的介绍 如下:
ABAC 有这么多优势,但它无法得到广泛地使用是因为其以决策导向,在性能上相对较弱,尤其是对于高频访问的操作而言,这个因素影响很大。
ABAC 的热门实现可以参见 Casbin 项目。
笔者以 ABAC 为基础,设计了一个简化版本的模型:
权限决策模型的核心是将资源与各个对象关联起来,这种对象在该模型中称为权限主体,即针对谁做的权限。
权限主体有很多类型(rel_subject_kind),包含但不限于账号(ACCOUNT)、群组节点(GROUP_NODE)、角色(ROLE)、应用(APP)、租户(TENANT),一条权限可以指定同一权限主体类型的多条记录(rel_subject_ids),用逗号分隔。
权限决策可以选择到相应开放等级的资源(rel_resource_id),如果权限主体与资源同属于一个应用,那么自然可以关联,但如果是不同应用则要看对应的资源是否开放,如果资源 1000 在 T1 租户的 A1 应用下,而要权限主体在 T2 租户的 A2 应用下,那么只有当资源 1000 的开放等级类型(expose_kind)为 GLOBAL 时才能关联。
资源是可操作的对象但不包含操作这个动作本身,对于同一资源可以有很多的操作类型(action_kind),包含但不限于是否存在(EXISTS)、创建(CREATE)、修改(MODIFY)、获取(FETCH)、删除(DELETE)。
确定了权限主体及资源后还要明确他们的关系(subject_operator),支持但不限于等于(EQ)、不等于(NEQ)、包含(INCLUDE)、相似(LIKE),包含与相似多用于群组节点主体,由于群组节点的 ID 带上下级关系(见前文),所以通过包含与相似可以避免递归,方便地定位到祖父、子孙节点。
最后还要明确策略命中的处理方式(result_kind),常见于通过(ACCEPT)、拒绝(REJECT)。再复杂的可以扩展出修正(MODIFY)这一方式并给出修正逻辑,比如用户 A 命中了“商城订单表”资源的获取(FETCH)策略,需要自动在 SQL 语句中加上(create_by = ?,[A])以只显示用户 A 的订单,那么可以将 result_kind 设置为 MODIFY,并加上 result_process 字段,内容为包含 create_by = ?,[A]的可识别信息。
总结
最后附上整体模型架构,有兴趣的同学可以移步笔者新建的 dew-serviceless(https://github.com/ideal-world/dew-serviceless)项目(没错,不是 serverless,项目构建中,正在逐步完善),上述完整的 SQL 脚本在module/iam/src/main/resources/sql/init.sql
中。
关注我的公众号:
版权声明: 本文为 InfoQ 作者【孤岛旭日】的原创文章。
原文链接:【http://xie.infoq.cn/article/c9e52d580dfb0fb8bcdafe6fb】。文章转载请联系作者。
评论