Casbin 是一个高效强大的开源访问控制框架,它支持 ACL、RBAC、ABAC 等多种模型。
Model
,即模型
,是 Casbin 的一个重要组成部分,模型的定义简单而复杂,且充满学问。Model
的作用,是对权限模型的定义,例如:acl
、rbac
、abac
等权限模型。
模型配置主要有五个部分:[request_definition],[policy_definition],[role_definition],[policy_effect] 和 [matchers],分别表示请求定义、策略定义、角色定义、策略效果定义、匹配器,其中 [role_definition] 角色定义是用于基于角色的模型(RBAC),支持用 #
开头表示注释。
请求定义
[request_definition]
r = sub, obj, act
请求的定义,定义了决策器决策 enforce()
时传入的参数。sub, obj, act
就表示 enforce()
方法需传入 3 个参数,支持增加或删除参数数量,保证顺序和数量一一对应
即可。
定义的参数名也可以修改,例如,要表示用户对接接口地址的权限,
则请求可以定义为:
[request_definition]
r = uid, uri, method
那么决策时可以这样使用:
enforce(888, '/api/post/add', 'POST');
意思是需要决策 uid 为 888 的用户对接口 /api/post/add
是否具有 POST
请求的权限。
策略定义
[policy_definition]
p = sub, obj, act
策略定义,它定义了策略中值的含义及顺序,参数名和数量同样支持修改。
假设,我们的策略表有如下的策略记录:
v0 | v1 | v2 | v3 | v4 |
---|---|---|---|---|
p | 886 | /api/post/add | POST | 2025-01-10 08:16:01 |
p | 887 | /api/post/delete | DELETE | 2025-01-10 08:20:11 |
p | 888 | /api/post/list | GET | 2025-01-10 08:30:22 |
那么,我们的策略可以定义为:
[policy_definition]
p = uid, uri, method, created_at
这个四个参数就依次表示了策略中的 v1~v4
列,v0
可以理解为策略类型或分组,就是定义中的 p
。
那 Casbin
在加载策略的时候,就会按照这个对应关系加载,使用某条策略中的某个字段时可以用p.uid
的方式。
角色定义
[role_definition]
g = _, _
角色定义,表明了用户和角色的继承关系,通常用于基于角色的权限模型。
其中 _, _
,两个下划线,可以称作前向
和后项
,表示前向继承后项
,通常用于表示用户属于某个角色,或者角色继承另一个角色。
如果为 _, _, _
三个下划线,用于多租户模型,则最后一项表示多租户里的域
。
策略效果定义
[policy_effect]
e = some(where (p.eft == allow))
策略的定义的取值是固定值,并且是系统内置的硬编码
,不支持自定义。目前支持以下几种配置:
some(where (p.eft == allow))
,表示在所有命中的策略中,只要有一条allow
的策略,那么结果就是true
,通俗来讲,就是一票赞成制
。
!some(where (p.eft == deny))
,表示在命中的策略中,如果没有deny
的,那最终的决策结果就是true
,否则就是false
,即一票否决制
。
some(where (p.eft == allow)) && !some(where (p.eft == deny))
,表示在所有命中的策略中,要有一条allow
的策略,并且不能有deny
的策略,则最终决策结果就是true
,例如:只要有人赞成且没有人反对即通过。
priority(p.eft) || deny
,用于隐式/显式优先级模型,以命中的策略的eft
的值作为决策结果,如果没有命中,或者eft
没有明确的结果,那么就是false
。
subjectPriority(p.eft)
,用于基于用户和角色的层级关系的优先级模型。
匹配器
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
匹配器,是对匹配规则的定义,m 的值是一个表达式。在调用enforce(...)
方法进行决策执行的时候,会根据表达式中的变量带入运算执行表达式,依据表达式的执行结果来决定策略是否命中或未命中。
匹配器支持常用的算术运算符如 +, -, *, /
,以及一些逻辑运算符如 &&, ||, !
,并且还支持内置函数和自定义函数,像例子中的 g(r.sub, p.sub)
就是一个内置函数(g(...)
)。
这个表达式中的变量名就是前面请求定义、策略定义中的定义的名称,支持自行修改变量名,保证上下文一致即可。比如前文我们演示了uid, uri, method
这样的定义,那么表达式中可以这样使用r.uri == p.uri && r.method == p.method
。
关于表达式的解析运算的库,大多是第三方库,表达式的解析运算对性能有重要影响,可以参考官方文档。
最后
这篇文章主要介绍了 Casbin 中 Model 的语法,这些语法并不限定编程语言,同样适用于Java
PHP
Python
Go
等其他语言的 Casbin。
正如文章开头所说,可以看出 Casbin 的 Model 的语法及配置,简单而复杂,且充满学问。