訪問控制是指區(qū)分不同用戶對不同資源的訪問能力,在應(yīng)用系統(tǒng)中通常叫做權(quán)限管理
在做任何多用戶系統(tǒng)的時候,用戶權(quán)限管理都是整個系統(tǒng)中必不可少的部分,并且權(quán)限設(shè)計要做到既安全又清晰是一件不太容易的事情。
根據(jù)不同的場景,權(quán)限管理可以設(shè)計出各種不同的模型。
今天就給各位介紹一個訪問控制框架Casbin以及PERM元模型。
Casbin · An authorization library
元模型 PERM
如果,在做系統(tǒng)設(shè)計時,針對每一個資源和每一個用戶都編寫訪問規(guī)則將會是一個工作量很大的事情,并且對于動態(tài)變化的資源和用戶,這樣做是不可行的。因此我們需要定義一系列規(guī)則,這些規(guī)則的組合就是一個訪問控制模型。
PERM模型是由4個基礎(chǔ)(Policy,Effect,Request,Matchers)描述各個資源和用戶之間的相互關(guān)系。
Request 請求
定義了請求參數(shù)。一個基本的請求是一個元組對象,至少包含subject(訪問實體), object(訪問的資源)和 action(訪問方法)。
r={sub, obj,act}
它其實就是定義了傳入訪問控制匹配函數(shù)的參數(shù)名和順序。
Policy 策略
定義訪問策略的模型。其實就是定義Policy規(guī)則文檔中各字段的名稱和順序。
p={sub, obj, act} 或 p={sub, obj, act, eft}
注意:如果不定義 eft(策略結(jié)果),那么將不會去讀策略文件中的結(jié)果字段,并將匹配的策略結(jié)果都默認(rèn)為allow。
Matchers 匹配規(guī)則
Request和Policy的匹配規(guī)則。
例如: m = r.sub == p.sub && r.act == p.act && r.obj == p.obj
這條簡單又常見的匹配規(guī)則的意思就是,請求的參數(shù)(實體、資源和方法)都相等即在策略中能找到,那么返回策略結(jié)果(p.eft)。策略結(jié)果會保存在p.eft中。
Effect
用于將給定請求與最終結(jié)果匹配的策略組合/減少的策略的模型。可以理解為,對Matchers匹配后的結(jié)果再進行一次邏輯組合判斷的模型。
例如:e = some(where(p.eft == allow))
這句的意思是指,如果匹配策略結(jié)果p.eft 存在(some) allow的結(jié)果,那么最終結(jié)果就為 真
再看個例子:
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
這個例子組合的邏輯含義是:如果有匹配出結(jié)果為alllow的策略并且沒有匹配出結(jié)果為deny的策略則結(jié)果為真,換句話說,就是匹配的策略都為allow時才為真,如果有任何deny,都為假 (更簡單的說當(dāng)allow和deny同時存在時,deny優(yōu)先)
以上時PERM的模型定義的說明,接下來,用Casbin實戰(zhàn)一下
Casbin訪問控制需要兩個東西:訪問控制模型文件和策略文件,模型文件就是上文描述的內(nèi)容。
下圖說明了如何使用基于 PERM 的模型授權(quán)請求。

創(chuàng)建一個完整的模型文件
創(chuàng)建一個perm.conf文件,內(nèi)容如下
# Request definition
[request_definition]
r = sub, obj, act
# Policy definition
[policy_definition]
p = sub, obj, act, eft # 這里我們定義了eft,不使用默認(rèn)值
# Policy effect
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny)) # 這里使用了deny優(yōu)先
# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act #最簡單的匹配規(guī)則。請求的參數(shù)與策略參數(shù)一致時獲得策略結(jié)果
注意代碼中的注釋
創(chuàng)建一個policy.csv文件, 其中的每個字段的定義就如perm中[policy_definition]中定義的順序:
p, zeta, data1, read, allow
p, bob, data2, write, allow
p, zeta, data2, write, deny
p, zeta, data2, write, allow
p 代表策略組名稱,就是metchers里對應(yīng)的那個p。后面的zeta,data, read, allow對應(yīng)的就是策略定義中的sub,obj,act和策略結(jié)果eft。
假如,request參數(shù)在策略文件中能夠匹配(zeta,data1和read),那么結(jié)果為allow;
假如,request參數(shù)在策略文件中能夠匹配(zeta,data2,write),那么結(jié)果為deny,同時也匹配另一條策略結(jié)果為allow,根據(jù)policy_effect的定義,依然識別為假。
接下來用Go代碼檢驗一下
創(chuàng)建main.go 代碼如下:
package main
import (
“fmt”
“github.com/casbin/casbin”
)
func main() {
//通過策略文件和模型配置穿件一個casbin訪問控制實例
e := casbin.NewEnforcer(“./perm.conf”, “./policy.csv”)
//定義各種sub,obj和act的數(shù)組
subs := []string{“bob”, “zeta”}
objs := []string{“data1”, “data2”}
acts := []string{“read”, “write”}
//遍歷組合sub,obj,act并打印出對應(yīng)策略匹配結(jié)果。
for _, sub := range subs {
for _, obj := range objs {
for _, act := range acts {
fmt.Println(sub, “/“, obj, “/“, act, “=“, e.Enforce(sub, obj, act))
}
}
}
}
這段Go代碼很簡單,組合每一種sub、obj和act,然后打印出訪問控制的結(jié)果驗證我們的策略文件和模型的設(shè)計。
運行結(jié)果為:
bob / data1 / read = false
bob / data1 / write = false
bob / data2 / read = false
bob / data2 / write = true
zeta / data1 / read = true
zeta / data1 / write = false
zeta / data2 / read = false
zeta / data2 / write = false
bob的策略很簡單,只有data2的write結(jié)果為allow,因此其余都是false,結(jié)果正確;
zeta對data1的read結(jié)果為allow,對data2的write同時有allow和denny(根絕policy_effect定義的deny優(yōu)先),因此結(jié)果zeta也只對 data1的read 為true,結(jié)果正確。
這樣,我們就使用Casbin和PERM創(chuàng)建了一個基礎(chǔ)的訪問控制模型設(shè)計和策略。
在實際應(yīng)用上,如果我們做的是一個Web應(yīng)用,可以將路由作為obj,請求方式Method作為act,登錄用戶的角色作為sub,在每一次請求時,把這3個參數(shù)傳遞給e.Enforce, 就可以實現(xiàn)對Web頁面和請求接口的權(quán)限控制管理,非常方便。
高級
存儲
Casbin除了能夠通過策略文件和模型配置文件設(shè)置訪問控制外,還可以適配數(shù)據(jù)庫模式,將策略和模型保存在數(shù)據(jù)庫中,更適合大型復(fù)雜的軟件系統(tǒng)的權(quán)限管理。
model存儲
policy存儲
函數(shù)
文中的模型配置沒有使用額外的函數(shù),但是在實際應(yīng)用中,對與資源的匹配模式,action的匹配模式可能會用到更高級的匹配方法。利用函數(shù)是最佳實踐方式。
Policy存儲 · Casbin
API
Casbin提供給了很多API用于管理 管理 API · Casbin