最近同事在研究Casbin的權限設計,咱們主要是考慮使用ABAC基於屬性的訪問控制,Casbin給的示例很少,因而本身寫了幾個示例。git
首先咱們看看提到ABAC時,通常描述以下:github
ABAC被一些人稱爲是權限系統設計的將來。測試
不一樣於常見的將用戶經過某種方式關聯到權限的方式,ABAC則是經過動態計算一個或一組屬性來是否知足某種條件來進行受權判斷(能夠編寫簡單的邏輯)。屬性一般來講分爲四類:用戶屬性(如用戶年齡),環境屬性(如當前時間),操做屬性(如讀取)和對象屬性(如一篇文章,又稱資源屬性),因此理論上可以實現很是靈活的權限控制,幾乎能知足全部類型的需求。lua
例如規則:「容許全部班主任在上課時間自由進出校門」這條規則,其中,「班主任」是用戶的角色屬性,「上課時間」是環境屬性,「進出」是操做屬性,而「校門」就是對象屬性了。爲了實現便捷的規則設置和規則判斷執行,ABAC一般有配置文件(XML、YAML等)或DSL配合規則解析引擎使用。spa
這裏咱們就以這個班主任上課進出校門爲例,看看在Casbin下是如何實現的:設計
首先,咱們定義用戶環境和對象,操做咱們就直接用字符串code
type Person struct{ Role string Name string } type Gate struct{ Name string } type Env struct{ Time time.Time Location string } func (env *Env) IsSchooltime() bool{ return env.Time.Hour()>=8&&env.Time.Hour()<=18 }
接下來咱們根據這個權限描述,咱們能夠寫出以下的Casbin PERM模板:
[request_definition] r = sub, obj, act, env [policy_definition] p = sub, obj,act [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.Time.Hour >=8 && r.env.Time.Hour <= 18
由於咱們給Env對象定義了IsSchooltime方法,因此咱們也能夠把目標寫成以下,也是同樣的效果:
[request_definition] r = sub, obj, act, env [policy_definition] p = sub, obj,act [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.IsSchooltime()
接下來咱們構造兩我的,一個是學生Yun,一個是老師Devin,構造兩個門,一個是工廠大門,一個是學校大門,操做的方法咱們就定義進門In和控制大門Control兩個操做,環境上咱們定義一個是早上9點,一個是晚上23點。
完整代碼以下:
func TestTeacherEnterSchoolGate() { p1 := Person{Role: "Student", Name: "Yun"} p2 := Person{Role: "Teacher", Name: "Devin"} persons := []Person{p1, p2} g1 := Gate{Name: "School Gate"} g2 := Gate{Name: "Factory Gate"} gates := []Gate{g1, g2} const modelText = ` [request_definition] r = sub, obj, act, env [policy_definition] p = sub, obj,act [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.Time.Hour >7 && r.env.Time.Hour <= 18 ` //m = r.sub.Role=='Teacher' && r.obj.Name=='School Gate' && r.act in('In','Out') && r.env.IsSchooltime() m := model.Model{} m.LoadModelFromText(modelText) e := casbin.NewEnforcer(m) envs := []*Env{InitEnv(9), InitEnv(23)} for _, env := range envs { fmt.Println("\r\nTime:",env.Time.Local()) for _, p := range persons { for _, g := range gates { pass := e.Enforce(p, g, "In", env) fmt.Println(p.Role, p.Name, "In", g.Name, pass) pass = e.Enforce(p, g, "Control", env) fmt.Println(p.Role,p.Name, "Control", g.Name, pass) } } } } func InitEnv(hour int) *Env{ env:=&Env{} env.Time=time.Date(2019,8,20,hour,0,0,0,time.Local) return env }
最後,輸出結果以下:
Time: 2019-08-20 09:00:00 +0800 CST
Student Yun In School Gate false
Student Yun Control School Gate false
Student Yun In Factory Gate false
Student Yun Control Factory Gate false
Teacher Devin In School Gate true
Teacher Devin Control School Gate false
Teacher Devin In Factory Gate false
Teacher Devin Control Factory Gate false
Time: 2019-08-20 23:00:00 +0800 CST
Student Yun In School Gate false
Student Yun Control School Gate false
Student Yun In Factory Gate false
Student Yun Control Factory Gate false
Teacher Devin In School Gate false
Teacher Devin Control School Gate false
Teacher Devin In Factory Gate false
Teacher Devin Control Factory Gate false
咱們能夠看到,在上課時間早上9點,學生是禁止進出校門,而只有老師Devin的進校門操做被經過。而到了晚上23點,老師Devin也不容許進校門了。對象
這裏須要注意的是,在通常的模板中,是沒有env這個環境變量的,我把它加到了request_definition的最後面寫成r = sub, obj, act, env,同時e.Enforce(sub,obj,act,env)須要按順序傳入4個參數。blog
我還會對Casbin的ABAC進一步的研究,各測試用例會發布到https://github.com/studyzy/abactest 有興趣的能夠看看。資源
最後,關於Casbin採用的規則引擎爲,https://github.com/Knetic/govaluate,編輯Matchers規則能夠參考:https://github.com/Knetic/govaluate/blob/master/MANUAL.md