Casbin
官方文檔:概述 | Casbin
TIP
本文只能算是一個Casbin入門文章,如果想要更細致的了解請前往官網進行學習。
介紹
在一個系統中,後端程序員需要負責對於API權限的管理,而這需要耗費大量的工作,倘若每一個項目都要自己手寫一套,將會浪費大量的時間。擁有更多人力物力的大公司會更傾向於自己開發一套權限框架,但是大部分中小公司承受不起這種開發成本,所以市面上開源的權限框架成為了他們的首選。Casbin就是這樣一個開源高效的訪問控制庫,本身是采用Go語言進行開發,同時也支持其他的主流語言。
需要注意的是,Casbin僅僅只是一個訪問控制框架,只負責訪問控制,訪問認證方面的邏輯並不由Casbin負責,它僅僅存儲用戶與角色之間的映射關系。支持以下訪問控制模型:
- ACL (Access Control List, 訪問控制列表)
- 具有超級用戶的ACL
- 沒有用戶的 ACL: 對於沒有身份驗證或用戶登錄的系統尤其有用。
- 沒有資源的 ACL: 某些場景可能只針對資源的類型, 而不是單個資源, 諸如
write-article,read-log等權限。 它不控制對特定文章或日志的訪問。 - RBAC (基於角色的訪問控制)
- 支持資源角色的RBAC: 用戶和資源可以同時具有角色 (或組)。
- 支持域/租戶的RBAC: 用戶可以為不同的域/租戶設置不同的角色集。
- ABAC (基於屬性的訪問控制): 支持利用
resource.Owner這種語法糖獲取元素的屬性。 - RESTful: 支持路徑, 如
/res/*,/res/: id和 HTTP 方法, 如GET,POST,PUT,DELETE。 - 拒絕優先: 支持允許和拒絕授權, 拒絕優先於允許。
- 優先級: 策略規則按照先後次序確定優先級,類似於防火牆規則
工作原理
在Casbin中,訪問控制模型被抽象為基於PERM的配置文件,PERM指Policy(策略),Effect(效果),Request(請求),Matcher(匹配),在項目修改授權機制時,只需要簡單地修改配置文件即可。一個正常的Model配置文件內容如下:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act這是一個最簡單的ACL訪問控制模型。
策略
在配置文件中,策略定義部分為
[policy_definition]
p = sub, obj, actp即指policy,不能用其他字符代替,sub指subject,為策略主體,obj即object,為策略對象,act即action,指的是行為。
p = sub, obj, act也可以有第四個字段eft,如果省略默認eft為allow。
p=sub, obj, act, eft這一行定義只是描述了policy該如何書寫,並非具體的策略定義。下面是一個具體的policy例子
p, jojo, cake, eatp代表了這是一條策略規則定義,jojo即策略主體,cake即策略對象,eat即行為,完整意思為主體jojo能對對象cake進行行為eat。具體的策略規則並不會出現在模型文件中,會有專門的policy文件或者數據庫來進行策略存儲。
請求
在配置文件中,請求定義部分為
[request_definition]
r = sub, obj, actr即指request,不能用其他字符代替,sub即subject,指請求主體,obj即object,指請求對象,act即action,指的是請求行為。一般情況下請求定義與策略定義字段名都一致。請求部分並不由casbin負責,這由開發者自己決定什麼是請求主體,什麼是請求對象,casbin只需要負責根據傳入的字段來進行訪問控制。
匹配
在配置文件中,匹配定義部分為
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actm指matcher,不能使用其他字符代替,其後就是相應的匹配規則,上述就是一個簡單的布爾表達式,其意為傳入的請求的所有字段都與策略規則的字段全部相同就匹配,當然它也可以是通配符或者表達力更強的正則表達式。
除此之外,matcher還支持in語法,例如
[matchers]
m = r.sub in ("root","admin")也可以是
[matchers]
m = r.sub.Name in (r.obj.Admins)e.Enforce(Sub{Name: "alice"}, Obj{Name: "a book", Admins: []interface{}{"alice", "bob"}})在進行匹配時,Casbin不會進行類型檢查,而是將其作為interface進行==檢查是否相等。
效果
效果定義部分對匹配結果再次作出邏輯組合判斷,在配置文件中,效果定義部分為
[policy_effect]
e = some(where (p.eft == allow))e即指effect,不能使用其他字符代替。 some 量詞判斷是否存在一條策略規則滿足匹配器。 any 量詞則判斷是否所有的策略規則都滿足匹配器 。
some(where (p.eft == allow))這一條規則意為在匹配結果中有一條結果allow,那麼最終結果就為allow。
e = !some(where (p.eft == deny))這一條規則意為在匹配結果中只要不存在deny的結果,那麼最終結果就為allow。
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))這一條規則意味在匹配結果中,有一條為allow,且不存在deny的結果,那麼最終結果就為allow。
雖然Casbin設計了上述政策效果的語法,但目前的執行只是使用硬編碼的政策效果。 他們認為這種靈活性沒有多大必要。 目前為止你必須使用內置的 policy effects,不能自定義,內置支持的 policy effects如下。
| Policy effect定義 | 意義 | 示例 |
|---|---|---|
| some(where (p.eft == allow)) | allow-override | ACL, RBAC, etc. |
| !some(where (p.eft == deny)) | deny-override | 拒絕改寫 |
| some(where (p.eft == allow)) && !some(where (p.eft == deny)) | allow-and-deny | 同意與拒絕 |
| priority(p.eft) || deny | priority | 優先級 |
| subjectPriority(p.eft) | 基於角色的優先級 | 主題優先級 |
TIP
1.上述四個定義都可以定義多個,語法是type+number,例如r2,p2,e2,m2。
2.模型文件可以有注釋,以#符號進行注釋。
示例
下面是一個示例,演示下模型文件的工作過程。首先定義一個簡單的ACL模型文件如下
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actPolicy文件如下
p, alice, data1, read
p, bob, data2, write如何抽象出主體,對象,行為這一過程由業務邏輯決定,這裡並不重要所以省略。下面以最簡單的方式展示傳入的請求,如下
alice, data1, read
bob, data1, read
alice, data2, write
bob, data2, writepolicy文件中定義了alice擁有對data1進行read操作的權限,bob擁有對data2進行write操作的權限,那麼在傳入的請求中
alice, data1, read表示alice想要對data1進行read操作,
bob, data1, read表示bob想要對data1進行read操作,余下的同理。那麼最終結果為
true
false
false
true這是一個最簡單的ACL示例,Casbin官網中可以進行在線編輯並測試示例,前往Casbin editor進行測試。
RBAC
RBAC(Role-Based-Access-Controll),基於角色的訪問控制,相較於ACL模型會多一個[role definition],下面是一個簡單的RBAC模型
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act其中角色的定義如下
[role_definition]
g = _, _g指group,不能用其他字符代替,支持type+number方式創建多個,_是佔位符,表示有幾個入參。一般而言,在Policy中,g通常為如下格式
g, alice, data2_admin
g, mike, data1_admin
g, data1_admin data2_adminalice指的是主體,data2_admin指的是角色,嚴格來說casbin都將將其看待為字符串,如何理解其含義和使用取決於開發者。
g, alice, data2_admin表示alice具有角色data2_admin
g, mike, data1_admin表示mike具有角色data1_admin
g, data1_admin data2_admin表示角色data1_admin具有角色data2_admin,這是角色之間的繼承關系。
資源角色模型
資源角色模型新增了一個g2,作為資源的角色定義,模型定義如下
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
g2 = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.actPolicy示例定義如下
p, alice, data1, read
p, bob, data2, write
p, data_group_admin, data_group, write
g, alice, data_group_admin
g2, data1, data_group
g2, data2, data_group其中g2定義了資源角色組,將資源賦予不同的角色,同時規定了用戶角色與資源角色之間的用戶關系。
p, data_group_admin, data_group, write這一條策略便是定義了具有角色data_group_admin的用戶能對具有data_group角色的資源進行寫操作。
多租戶領域模型
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _, _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act多租戶領域模型相較於傳統RBAC模型多了dom字段,用於表示主體所屬於的領域。Policy示例如下
p, admin, domain1, data1, read
p, admin, domain1, data1, write
p, admin, domain2, data2, read
p, admin, domain2, data2, write
g, alice, admin, domain1
g, bob, admin, domain2例如
p, admin, domain1, data1, read定義了屬於領域domain1的主體admin具有對data1進行read操作的權限
g, alice, admin, domain1定義了alice屬於domain1具有角色admin
