权限,设计、实现、平台接入。

这篇文章讲述。
权限可以全部转化为访问控制。
访问控制就是访问控制矩阵的记录和查询。
用户组、RBAC、ABAC、PBAC就是帮我们管理好访问控制矩阵。
想要访问控制的管理层度越细,则method+url映射到表达元素的方式需要越精细。
映射方式由粗犷到精细,依次出现 —— url映射、method+url、url路径参数、语义化api。
RBAC如何管理需求,做好功能设计。
ABAC又如何,
PBAC的语义设计和url的语义化细节如何。
最后,某些点位实在不想把权限转化为访问控制,又该如何操作。


设计部分


一、 需求管理

To B的产品,业务上往往会涉及到权限。

这些业务上的要求为:

  • 一些人能做某些事,而另一些人无法做某些事。
  • 同样的视角,一些人所见数据,另一些人所见数据,各不相同。
  • 一些人在控制台的视角所见页面,跟另一些人不一样。

用比喻的手法来说明,

  • 需求一, 有人能进门,有人不能进这个门。
  • 需求二, 不同的人进门后所见所得,不一致。
  • 需求三, 有人能看见门,另一些人连门都看不见。

当面临这些业务需求时,直觉上,我们的想法是: 是时候做一些权限相关的开发工作了。
为此,我们衍生出了一系列的业务、技术概念,如角色、用户组、RBAC、ABAC等,帮助我们去做我们直觉上的权限工作。

但其实第一步,应该做好需求上的管理。

比如需求二,完全可以设计不同门,门后放置不同的风景。想让谁见到怎样的风景,就让这批人进入怎样的门。这样就从实现需求二,转而变为了实现需求一即可。
实际上的例子,学校后台管理系统中,校长可以进入"校长办公室" 页面,而老师不允许进入。

又比如需求三,不想让人看见的门,前置另一道门。当人可以通过这道前置的门时,才可以见到后面的门。那么就从实现需求三,变为实现需求一即可。
实际的例子,依然是学校后台管理系统,老师可以登录,进入系统,而学生却无法登入。

这里下一个定论,一切的权限相关的需求,皆可以设计为访问控制
访问控制,即需求一的需求。
换言之,只要实现了访问控制,就可以通过一些设计,表达出权限相关的全部业务需求。

Q: 如果那个学校后台管理系统,不想让老师看见"校长办公室", "校长秘密通道", 这一系列的tab页,我该如何设计,才能转化为访问控制?
A: 将原来的学校后台管理系统,分为老师端和校长端,分属不同的web app,即可转化为访问控制。这样会涉及到成本问题,所以后文对需求二和需求三的设计,再做一番讨论。

二、 访问控制判断设计

为完成访问控制的判断,先剖析请求行为。
一次http请求中,具有对应的http method,和http url。

而一次访问,还具有另一个上下文。
即这次访问发起的主体。
这个主体通过身份验证获取到,塞入上下文之中。

http请求.png

如图所示,权限鉴定之时,已经具有method、url、principal的上下文。
通过method和url,我们唯一定位到这次访问要去往的地方。
即与我们上文所比喻的门一一对应。
而principal则代表了访问控制中的人。

一次http请求是否被授权,即为一次访问控制的判断过程。
也即为通过principal、method、url去寻找判断结果的过程。

访问控制矩阵.png

为实现这个过程,需要事先建立访问控制矩阵。
建立之后,可由人、门两个上下文,去查询矩阵记录,获知判断结果。


三、 访问控制管理

访问控制矩阵卷帙浩繁,维护和使用成本都很高。
为此,设计上一般在遵循一些原则。
比如,无记录,则视为无法通过。
无兵符,则无法点将;无玉玺,不是皇帝。
没有记录,默认不允许通过。

另外,还有概念上的设计,帮助我们去归聚人、门。

归聚前.png

归聚后.png

用户组这个概念,从"人"的角度出发,将"人"归聚到一起。
组织部门,人员关系是既有的认知,可利用此既有认知帮助我们完成归聚。
例如部门x的成员,份数用户组x,理所应当。

RBAC,基于角色的访问控制,角色本身,从"门"的角度出发,将"门"归聚到一起。
业务的进行和归纳,会自然演化出角色,可通过角色上的认知,帮助归聚。
例如教师这一角色,能访问管理学生,管理试卷的页面。

如上图所示,归聚之前,人员2和3,皆可访问门2和3,但相应会产生四条记录。
归聚之后,只需记录用户组x到角色y的一条记录。即可拥有同样的信息密度。

ABAC,基于属性(或标签)的访问控制,与角色一样仍然是从"门"的角度触发,将"门"归聚到一起。
只要门2、门3,具有相同的属性,那么即可归聚到一起。

并且,RBAC是ABAC的子集,可以用ABAC兼容掉RBAC。

绑定到角色.png

绑定到标签.png

如图所示,建立标签role,原来归聚到角色x的资源 1,2,3绑定到标签role并且值为x,
原来绑定到角色x的人,绑定到标签 role=x。ABAC就兼容掉了RBAC。

另外,权限管理上的角色概念,是为了将归聚"门"的任务与业务概念的联系变得更紧密而出现。
但这个概念本身,并不适配它的任务。
它总是容易跟业务角色联想到一起,导致遗忘了它的任务根本与人不相关。

对"门"的归聚,若要强行与一个角色概念绑定到一起,当控制粒度需要更细时,最终会被角色概念所缚累。

比如教师有不同年级的教师,若要细粒度的对不同年级的"门"进行控制,则势必会出现角色"一年级教师"、"二年级教师"、"三年级教师"。若要粒度更细,则"一班教师"、"二班教师"此类角色又要出现了,进而会产生role explosion

考虑基于属性的方式去归聚,"门"打上属性,班级=一班,年级=二年级。
而"人"也附加在属性年级=二年级,班级=一班。
人与门的对应属性值相同,于是可以进入。

从上面那个例子上可以看出,角色只是找个概念去归聚而已。
荃者所以在鱼,得鱼而忘荃,言者所以在意,得意而忘言。
当需要更细粒度的归聚的时候,放弃角色的概念,使用ABAC,能帮你在设计上走的更为畅通。

更多与关于ABAC的资料

PBAC, policy base access control,一个policy采用json格式的领域特定语言,表达出语义,归聚"门"。
policy完全不用跟业务概念绑定在一起,故是最灵活,粒度也最为细致。丰富的特定语义和占位符,可以将表述玩的花里胡哨。但也最具复杂度,离业务概念最远。

各模式的业务概念层度.png

并且,ABAC兼容RBAC,而PBAC兼容一切。


四、应对变化

随着软件的迭代,业务的进行,业务上也会出现许多变化。访问控制需要适应这些相应的变化,以满足对应的业务需求。

访问控制矩阵中,"人"的维度发生变化,是最容易适应的。
人员的产生和消失,可以简单的对应到访问控制矩阵的记录的产生和消失。
加入和退出某个用户组,可以简单的对应到用户组跟人的绑定记录的产生和消失。
这是因为,无论是"人"还是用户组的概念,它们的变化跟业务的变化天然契合。
业务上不会去设计或者发展出这些概念无法覆盖的地方。

复杂的部分,在于访问控制矩阵的另一个维度。
"门"。
"门"的新增和消失,依旧可以简单对应到访问控制矩阵的记录的产生和消失。
角色、属性的变化,依然可以是某个"门"与之绑定的角色、属性的绑定记录的产生和消失。

不过如何将这种变化,与业务的变化匹配好,则并不简单。

因为,若使用角色的概念,则角色的概念并不完全匹配归聚业务。
而若使用属性,那么属性跟业务如何契合,又考验设计者的联想能力。

而且,"门"的设计实现,并不简单。
业务形形色色,想要的表达太多,欲壑难填。
故除了method+url的简单组合外,往往会出现另外的表达。
例如aws的policy,有通配符,condition等语法和属性,可以让一个policy表达出复杂的语意。

所以,有两点建议。

  • 一者,设计风格固定。以使归聚概念固定。
    风格固定,RBAC能满足你的业务,就用RBAC, 一开始决定要上ABAC则上ABAC,不要沉浸在类似policy这类具体的实现之中,而忘记了自己的设计风格。或者干脆一开始就没有自己的设计风格。
  • 二者,做增量式的变化。以使得容易回滚和版本控制。




实现部分


五、租户,用户,用户组

to b的产品,若做私有化交付,那么可以不必考虑租户这个概念。
每一套交付,都是一套新的租户。

若是类似云服务的场景。租户的实现则有多种。
最简单的一种,是在数据存储的表结构上,增加租户id的记录。
查询数据时,从验身过后的上下文中拿到租户id,从而进行数据筛选。

若是这样的手法,那么租户的概念,隐藏在了数据访问层。
每个租户,都以为自己独占了系统。故仍可以当作私有化部署场景。

用户和用户组,则比较简单,实现上契合业务概念即可。


用户与用户组.png


六、从url,method映射到"门"

url和method到"门"的映射,表达的越精细,则可以归聚到的粒度自然就越细腻。

6.1 url 与表达元素一一映射

最粗犷简单的表达为,完全抛弃http的method, 仅用url映射要去往的门。

映射精细层度一.png

这时,url完全等于聚合记录中的表达元素。
例如角色x,包含元素 1,2,3。而元素1,2,3的值跟url一一对应。

6.2 method+url,组合表达,帮助结合业务概念

稍微再精细一点,http的method可跟url结合在一起,组合表达。

映射精细层度二.png

例如,restful的设计风格,url代表资源,是一个名词,而相应的http method代表动词。
组合起来后,等于这次http访问会对这个资源做一次怎样的操作。
角色x绑定的主体,只能对此资源进行查询,
角色y绑定的主体,能对此资源进行更新,创建,删除。

这样的风格设计,对归聚并无太大帮助,因为完全可以用各种不同的url代表method+url。
但此种风格设计,将业务表达为对资源做操作,使得"门"的表达从千姿百态转化为一个统一的定式:
权限表达元素 = 资源 + 操作
通过这样的定式,业务概念、业务设计,将与权限设计较好的结合。

6.3 路径参数,精细到具体资源

精细层度再进一步,url中出现路径参数。譬如:
storage/{accountId}/myStorageList
这个url代表访问自己的存储列表。路径中{accountId}代表了这个账户本身的id。
若忽略路径参数,例如:
storage/myStorageList
依然能够实现相应的业务功能,但是对归聚的粒度,表达力就不够了。

此时,若表达元素中的url部分为:
sotrage/357/myStorageList
则会相当精细的表达出这样的"门" —— 账号id为357的存储列表。

当然,通常会在表达元素中相应增加一些语法,以降低表达元素的维护成本。

{
    "method": "GET",
    "url" : "sotrage/${selfAccountId}/myStorageList" 
}

通过语法${selfAccountId}, 指代了绑定主体的账户id,当此表达元素被绑定到主体之上时,即可解析展开为具体的表达。

6.4 富语义api设计

路径参数,往往是id、name等某个业务实体的标识,故当使用这样的表述方式时,已经将url变作了对资源的表达。

api的设计自然转变成为对资源进行操作,那么结合restful风格,或者google api设计规范的风格,就变得较为自然。

再精细一点,可以从url中解析出来该对应资源的丰富信息。
举例,假设aws的某个url设计为:
s3/buckets/{bucketsId}
那么可以解析出ARN:
arn:aws:s3:::buckets:{bucketsId}

aws的ARN全称为亚马逊资源名称,具有固定的格式,
arn:partition:service:region:account-id:resource-type:resource-id
上文省略了region和account-id,并且partition分区可通过验身信息找到。
具体的ARN的格式,可看这里: AWS资源名称
可参考aws的ARN,做自己的实现。也可以自行设计一套富语义api,只要能解析出你对资源的表达名称即可。

归聚方式支撑与映射精细层度.png

最后,method,url的映射方式精细,归聚细粒度细的归聚方式,才能得到支撑。
若映射不精细,则更细粒度的PBAC、ABAC等归聚方式无法支持。
当然,越精细,对设计者、实现者的要求就越高,技术负担就越重。
一般的to B业务,都是在RBAC层面为止。


七、RBAC

访问控制矩阵过于庞大,维护代价大,很难跟着业务走,此不必赘言。
RBAC帮助我们做归聚,是以角色这个概念为出发,将实际的业务需求,关联到权限之上的。
实现RABC的要诀在于,是保持业务角色和权限角色上的匹配。

比如这样的需求:

  • 做一个任务列表接口
  • 管理人员,有权限能看到全部的任务。
  • 普通人员,只能看到自己相关的任务。

解读此直觉上的需求,给出直觉上的设计:

  • 给出任务列表接口
  • 区分管理员和普通用户
  • 如果为管理员,返回全部任务
  • 如果为普通用户,返回关联的任务

从功能角度来讲,这个接口的功能,不够简单清晰。
从设计角度来讲,这个接口服务的群体不够单一,它既对管理员负责,也对普通用户负责。
并且,若要以RBAC的方式,做好这个接口的访问控制,不够。

重新设计为:

  • 接口1,返回全部任务列表。
  • 接口2,返回被分配到的任务列表。

拆分为此两个接口后,接口1只对业务角色管理员这一个群体负责,并可以对应到权限角色上的"任务管理员"。
接口2只对业务上的普通用户负责,也可对应到权限角色"任务执行者"。

业务角色管理员还会负责分配任务,将普通用户跟任务绑定到一起。分配任务这一行为,也可以归聚在权限角色"任务管理员"之中。

RBAC的应用与实现,可见于此。

使用RBAC做归聚,又会遇到RBAC的天然缺陷,即角色概念与归聚任务,并不适配。
夸张点说牛头不对马嘴。

不过未必在感受到不匹配,或者粒度不够时,就考虑上ABAC或者PBAC。
我们开篇使用了需求管理,将相应权限的直觉需求,全部转化为了访问控制。
那么其实也可以使用需求管理,做好功能设计,消除不适配感。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容