# 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
~~~