ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Model语法 * Model CONF 至少应包含四个部分:`[request_definition], [policy_definition], [policy_effect], [matchers]`。 * 如果 model 使用 RBAC, 还需要添加`[role_definition]`部分。 * A model CONF can contain comments. The comments start with`#`, and`#`will comment the rest of the line. ## Request定义 `[request_definition]`部分用于request的定义,它明确了`e.Enforce(...)`函数中参数的含义。 ~~~ini [request_definition] r = sub, obj, act ~~~ `sub, obj, act`表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)。 但是, 你可以自定义你自己的请求表单, 如果不需要指定特定资源,则可以这样定义`sub、act`,或者如果有两个访问实体, 则为`sub、sub2、obj、act`。 ## Policy定义 `[policy_definition]`部分是对policy的定义,以下文的 model 配置为例: ~~~ini [policy_definition] p = sub, obj, act p2 = sub, act ~~~ 这些是我们对policy规则的具体描述 ~~~ p, alice, data1, read p2, bob, write-all-objects ~~~ policy部分的每一行称之为一个策略规则, 每条策略规则通常以形如`p`,`p2`的`policy type`开头。 如果存在多个policy定义,那么我们会根据前文提到的`policy type`与具体的某条定义匹配。 上面的policy的绑定关系将会在matcher中使用, 罗列如下: ~~~ (alice, data1, read) -> (p.sub, p.obj, p.act) (bob, write-all-objects) -> (p2.sub, p2.act) ~~~ **注1**: 当前只支持形如`p`的单个policy定义, 形如`p2`类型的尚未支持。 通常情况下, 用户无需使用多个 policy 定义, 如果您有其他情形的policy定义诉求,请在[https://github.com/casbin/casbin/issues/new提出issue告知我们](https://github.com/casbin/casbin/issues/new%E6%8F%90%E5%87%BAissue%E5%91%8A%E7%9F%A5%E6%88%91%E4%BB%AC)。 **注2**: policy定义中的元素始终被视为字符串(`string`)对待, 如果您对此有疑问,请移步[https://github.com/casbin/casbin/issues/113](https://github.com/casbin/casbin/issues/113) ## Policy effect定义 `[policy_effect]`部分是对policy生效范围的定义, 原语定义了当多个policy rule同时匹配访问请求request时,该如何对多个决策结果进行集成以实现统一决策。 以下示例展示了一个只有一条规则生效,其余都被拒绝的情况: ~~~ini [policy_effect] e = some(where (p.eft == allow)) ~~~ 该Effect原语表示如果存在任意一个决策结果为`allow`的匹配规则,则最终决策结果为`allow`,即allow-override。 其中`p.eft`表示策略规则的决策结果,可以为`allow`或者`deny`,当不指定规则的决策结果时,取默认值`allow`。 通常情况下,policy的`p.eft`默认为`allow`, 因此前面例子中都使用了这个默认值。 这是另一个policy effect的例子: ~~~ini [policy_effect] e = !some(where (p.eft == deny)) ~~~ 该Effect原语表示不存在任何决策结果为`deny`的匹配规则,则最终决策结果为`allow`,即deny-override。`some`量词判断是否存在一条策略规则满足匹配器。`any`量词则判断是否所有的策略规则都满足匹配器 (此处未使用)。 policy effect还可以利用逻辑运算符进行连接: ~~~ini [policy_effect] e = some(where (p.eft == allow)) && !some(where (p.eft == deny)) ~~~ 该Effect原语表示当至少存在一个决策结果为`allow`的匹配规则,且不存在决策结果为`deny`的匹配规则时,则最终决策结果为`allow`。 这时`allow`授权和`deny`授权同时存在,但是`deny`优先。 ## Matchers `[matchers]`原语定义了策略规则如何与访问请求进行匹配的匹配器,其本质上是布尔表达式,可以理解为Request、Policy等原语定义了关于策略和请求的变量,然后将这些变量代入Matcher原语中求值,从而进行策略决策。 ~~~ini [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act ~~~ 这是一个简单的例子,该Matcher原语表示,访问请求request中的subject、object、action三元组应与策略规则policy rule中的subject、object、action三元组分别对应相同。 Matcher原语支持+、 -、 \*、 /等算数运算符,==,、!=、 >、 <等关系运算符以及&& (与)、|| (或)、 ! (非)等逻辑运算符。 **注**: 虽然可以像其他原语一样的编写多个类似于`m1`,`m2`的matcher, 但是当前我们只支持一个有效的 matcher`m`。 通常情况下,您可以在一个matcher中使用上文提到的逻辑运算符来实现复杂的逻辑判断, 因而我们认为目前不需要支持多个matcher。 如果您对此有疑问,请告知我们([https://github.com/casbin/casbin/issues](https://github.com/casbin/casbin/issues))。 ### matcher中的函数 matcher的强大与灵活之处在于您甚至可以在matcher中定义函数,这些函数可以是内置函数或自定义的函数。当前支持的内置函数如下: | 函数 | 释义 | 示例 | | --- | --- | --- | | keyMatch(arg1, arg2) | 参数 arg1 是一个 URL 路径,例如`/alice_data/resource1`,参数 arg2 可以是URL路径或者是一个`*`模式,例如`/alice_data/*`。此函数返回 arg1是否与 arg2 匹配。 | [keymatch\_model.conf](https://github.com/casbin/casbin/blob/master/examples/keymatch_model.conf)/[keymatch\_policy.csv](https://github.com/casbin/casbin/blob/master/examples/keymatch_policy.csv) | | keyMatch2(arg1, arg2) | 参数 arg1 是一个 URL 路径,例如`/alice_data/resource1`,参数 arg2 可以是 URL 路径或者是一个`:`模式,例如`/alice_data/:resource`。此函数返回 arg1 是否与 arg2 匹配。 | [keymatch2\_model.conf](https://github.com/casbin/casbin/blob/master/examples/keymatch2_model.conf)/[keymatch2\_policy.csv](https://github.com/casbin/casbin/blob/master/examples/keymatch2_policy.csv) | | regexMatch(arg1, arg2) | arg1 可以是任何字符串。arg2 是一个正则表达式。它返回 arg1 是否匹配 arg2。 | [keymatch\_model.conf](https://github.com/casbin/casbin/blob/master/examples/keymatch_model.conf)/[keymatch\_policy.csv](https://github.com/casbin/casbin/blob/master/examples/keymatch_policy.csv) | | ipMatch(arg1, arg2) | arg1 是一个 IP 地址, 如`192.168.2.123`。arg2 可以是 IP 地址或 CIDR, 如`192.168.2. 0/24`。它返回 arg1 是否匹配 arg2。 | [ipmatch\_model.conf](https://github.com/casbin/casbin/blob/master/examples/ipmatch_model.conf)/[ipmatch\_policy.csv](https://github.com/casbin/casbin/blob/master/examples/ipmatch_policy.csv) | ### 如何添加自定义函数 首先准备好一个有几个参数和一个布尔值返回值的函数: ~~~go func KeyMatch(key1 string, key2 string) bool { i := strings.Index(key2, "*") if i == -1 { return key1 == key2 } if len(key1) > i { return key1[:i] == key2[:i] } return key1 == key2[:i] } ~~~ 然后用`interface{}`类型包装此函数: ~~~go func KeyMatchFunc(args ...interface{}) (interface{}, error) { name1 := args[0].(string) name2 := args[1].(string) return (bool)(KeyMatch(name1, name2)), nil } ~~~ 最后, 将该函数注册到 Casbin enforcer: ~~~go e.AddFunction("my_func", KeyMatchFunc) ~~~ 现在, 您可以像下面这样使用 model 中的函数: ~~~ini [matchers] m = r.sub == p.sub && my_func(r.obj, p.obj) && r.act == p.act ~~~