與你相識
部落客介紹:
– 本人是普通大學生一枚,每天鑽研計算機技能,CSDN主要分享一些技術内容,因我常常去尋找資料,不經常能找到合适的,精品的,全面的内容,導緻我花費了大量的時間,是以會将摸索的内容全面細緻記錄下來。另外,我更多關于管理,生活的思考會在簡書中釋出,如果你想了解我對生活有哪些反思,探索,以及對管理或為人處世經驗的總結,我也歡迎你來找我。
– 目前的學習專注于Go語言,輔學算法,前端領域。也會分享一些校内課程的學習,例如資料結構,計算機組成原理等等,如果你喜歡我的風格,請關注我,我們一起成長。
Table of Contents
- casbin
-
- 官方文檔
-
- 基礎知識
-
- 安裝及簡單實用
- 工作原理
- Model
-
- 支援的Model
- Model文法
-
- Request定義
- Policy定義
- Policy effect定義
- Matchers
-
- 内置函數
- RBAC
- ABAC
- 每日一庫——casbin
-
- ACL模型
- RBAC模型
-
- 多個RBAC
- 多層角色
- RBAC domain
- ABAC模型
- 模型存儲
- 政策存儲
-
- 使用函數
- 參考資料
casbin
權限管理幾乎在每個系統中都是必備的子產品。如果項目開發每次都要實作一次權限管理,會浪費很多的時間,而casbin就來做這個事情,支援常用的多種通路控制模型,如
ACL/RBAC/ABAC
等。可以實作靈活的通路權限控制。
比如說什麼角色,什麼使用者,可以通過某個api,就可以使用casbin來進行限制。
官方文檔
由于官方文檔到中間靠後的部分有點難以了解,是以就轉向其它教程了。
基礎知識
安裝及簡單實用
go get github.com/casbin/casbin
另外建立一個Casbin決策器需要有一個模型檔案和政策檔案作為參數:
import "github.com/casbin/casbin"
e := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")
然後可以在通路發生之前,給代碼添加強制挂鈎:
sub := "alice" // 想要通路資源的使用者。
obj := "data1" //要通路的資源。
act := "read" // 使用者對資源執行的操作。
if e.Enforce(sub, obj, act) == true {
// 允許alice讀取data1
} else {
// 拒絕請求,顯示錯誤
}
工作原理
casbin的通路控制模型被抽象為基于PERM(Policy(政策), Effect(效果), Request(請求), Matcher(比對器))的一個檔案。
Casbin中最基本,最簡單的model是
ACL
。
ACL
中的
model CONF
為:
# 請求定義
[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
// 對于過長的單元配置,也可以通過在結尾處添加“/”進行斷行
m = r.sub == p.sub && r.obj == p.obj \
&& r.act == p.act
policy
如下:
// 這表示alice可以讀取data1
p, alice, data1, read
// 這表示bob可以編寫data2
p, bob, data2, write
Model
支援的Model
- ACL (Access Control List, 通路控制清單)
- 具有超級使用者的 ACL
- 沒有使用者的 ACL: 對于沒有身份驗證或使用者登入的系統尤其有用。
- 沒有資源的 ACL: 某些場景可能隻針對資源的類型, 而不是單個資源, 諸如
,write-article
等權限。 它不控制對特定文章或日志的通路。read-log
- RBAC (基于角色的通路控制)
- 支援資源角色的RBAC: 使用者和資源可以同時具有角色 (或組)。
- 支援域/租戶的RBAC: 使用者可以為不同的域/租戶設定不同的角色集。
- ABAC (基于屬性的通路控制): 支援利用
這種文法糖擷取元素的屬性。resource.Owner
- RESTful: 支援路徑, 如
,/res/*
和 HTTP 方法, 如/res/: id
,GET
,POST
,PUT
。DELETE
- 拒絕優先: 支援允許和拒絕授權, 拒絕優先于允許。
- 優先級: 政策規則按照先後次序确定優先級,類似于防火牆規則。
Model文法
- Model CONF 至少應包含四個部分:
。[request_definition], [policy_definition], [policy_effect], [matchers]
- 如果 model 使用 RBAC, 還需要添加
部分。[role_definition]
Request定義
[request_definition]
部分用于request的定義,它明确了
e.Enforce(...)
函數中參數的含義。
[request_definition]
r = sub, obj, act
sub, obj, act
表示經典三元組: 通路實體 (Subject),通路資源 (Object) 和通路方法 (Action)。 但是, 你可以自定義你自己的請求表單, 如果不需要指定特定資源,則可以這樣定義
sub、act
,或者如果有兩個通路實體, 則為
sub、sub2、obj、act
。
Policy定義
[policy_definition]
部分是對policy的定義,以下文的 model 配置為例:
[policy_definition]
p = sub, obj, act
這些是我們對policy規則的具體描述
p, alice, data1, read
policy部分的每一行稱之為一個政策規則。 上面的policy的綁定關系将會在matcher中使用, 羅列如下:
Policy effect定義
[policy_effect]
部分是對policy生效範圍的定義, 原語定義了當多個policy rule同時比對通路請求request時,該如何對多個決策結果進行內建以實作統一決策。 以下示例展示了一個隻有一條規則生效,其餘都被拒絕的情況:
[policy_effect]
e = some(where (p.eft == allow))
該Effect原語表示如果存在任意一個決策結果為
allow
的比對規則,則最終決策結果為
allow
。 其中
p.eft
表示政策規則的決策結果,可以為
allow
或者
deny
,當不指定規則的決策結果時,取預設值
allow
。 通常情況下,policy的
p.eft
預設為
allow
, 是以前面例子中都使用了這個預設值。
這是另一個policy effect的例子:
[policy_effect]
e = !some(where (p.eft == deny))
該Effect原語表示不存在任何決策結果為
deny
的比對規則,則最終決策結果為
allow
,即deny-override。
some
量詞判斷是否存在一條政策規則滿足比對器。另外
any
量詞則判斷是否所有的政策規則都滿足比對器。 policy effect還可以利用邏輯運算符進行連接配接:
[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原語中求值,進而進行政策決策。
[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原語支援+、 -、 *、 /等算數運算符,==,、!=、 >、 <等關系運算符以及&& (與)、|| (或)、 ! (非)等邏輯運算符。
内置函數
函數 | 釋義 | 示例 |
---|---|---|
keyMatch(arg1, arg2) | 參數 arg1 是一個 URL 路徑,例如 ,參數 arg2 可以是URL路徑或者是一個 模式,例如 。此函數傳回 arg1是否與 arg2 比對。 | keymatch_model.conf/keymatch_policy.csv |
keyMatch2(arg1, arg2) | 參數 arg1 是一個 URL 路徑,例如 ,參數 arg2 可以是 URL 路徑或者是一個 模式,例如 。此函數傳回 arg1 是否與 arg2 比對。 | keymatch2_model.conf/keymatch2_policy.csv |
regexMatch(arg1, arg2) | arg1 可以是任何字元串。arg2 是一個正規表達式。它傳回 arg1 是否比對 arg2。 | keymatch_model.conf/keymatch_policy.csv |
ipMatch(arg1, arg2) | arg1 是一個 IP 位址, 如 。arg2 可以是 IP 位址或 CIDR, 如 。它傳回 arg1 是否比對 arg2。 | ipmatch_model.conf/ipmatch_policy.csv |
也可以添加自定義函數,具體參考:添加自定義函數
RBAC
看不懂
ABAC
看不懂
每日一庫——casbin
ACL模型
下面可以看到我們使用ACL模型進行的權限控制
我們依然使用 Go Module 編寫代碼,先初始化:
$ mkdir casbin && cd casbin
$ go mod init github.com/darjun/go-daily-lib/casbin
然後安裝
casbin
,目前是
v2
版本:
$ go get github.com/casbin/casbin/v2
權限實際上就是控制誰能對什麼資源進行什麼操作。
casbin
将通路控制模型抽象到一個基于 PERM(Policy,Effect,Request,Matchers) 元模型的配置檔案(模型檔案)中。是以切換或更新授權機制隻需要簡單地修改配置檔案。
policy
是政策或者說是規則的定義。它定義了具體的規則。
request
是對通路請求的抽象,它與
e.Enforce()
函數的參數是一一對應的
matcher
比對器會将請求與定義的每個
policy
一一比對,生成多個比對結果。
effect
根據對請求運用比對器得出的所有結果進行彙總,來決定該請求是允許還是拒絕。
編寫模型檔案:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
[policy_effect]
e = some(where (p.eft == allow))
上面模型檔案規定了權限由
sub,obj,act
三要素組成,隻有在政策清單中有和它完全相同的政策時,該請求才能通過。比對器的結果可以通過
p.eft
擷取,
some(where (p.eft == allow))
表示隻要有一條政策允許即可。
然後我們政策檔案(即誰能對什麼資源進行什麼操作):
p, dajun, data1, read
p, lizi, data2, write
上面
policy.csv
檔案的兩行内容表示
dajun
對資料
data1
有
read
權限,
lizi
對資料
data2
有
write
權限。
接下來就是使用的代碼:
package main
import (
"fmt"
"log"
"github.com/casbin/casbin/v2"
)
func check(e *casbin.Enforcer, sub, obj, act string) {
ok, _ := e.Enforce(sub, obj, act)
if ok {
fmt.Printf("%s CAN %s %s\n", sub, act, obj)
} else {
fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
}
}
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
代碼其實不複雜。首先建立一個
casbin.Enforcer
對象,加載模型檔案
model.conf
和政策檔案
policy.csv
,調用其
Enforce
方法來檢查權限。運作程式:
$ go run main.go
dajun CAN read data1
lizi CAN write data2
dajun CANNOT write data1
dajun CANNOT read data2
請求必須完全比對某條政策才能通過。
("dajun", "data1", "read")
比對
p, dajun, data1, read
,
("lizi", "data2", "write")
比對
p, lizi, data2, write
,是以前兩個檢查通過。第 3 個因為
"dajun"
沒有對
data1
的
write
權限,第 4 個因為
dajun
對
data2
沒有
read
權限,是以檢查都不能通過。輸出結果符合預期。
sub/obj/act
依次對應傳給
Enforce
方法的三個參數。實際上這裡的
sub/obj/act
和
read/write/data1/data2
是我自己随便取的,你完全可以使用其它的名字,隻要能前後一緻即可。
上面例子中實作的就是
ACL
(access-control-list,通路控制清單)。
ACL
顯示定義了每個主體對每個資源的權限情況,未定義的就沒有權限。我們還可以加上超級管理者,超級管理者可以進行任何操作。假設超級管理者為
root
,我們隻需要修改比對器:
[matchers]
e = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"
隻要通路主體是
root
一律放行。
驗證:
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "root", "data1", "read")
check(e, "root", "data2", "write")
check(e, "root", "data1", "execute")
check(e, "root", "data3", "rwx")
}
因為
sub = "root"
時,比對器一定能通過,運作結果:
$ go run main.go
root CAN read data1
root CAN write data2
root CAN execute data1
root CAN rwx data3
RBAC模型
ACL
在使用者和資源比較少的情況下沒有什麼問題,但是如果使用者很多的話,就會顯得非常的繁瑣,試想一下每次新增一個使用者,都要把他需要的權限重新設定一遍是多麼地痛苦。
是以
RBAC
就通過引入
角色(role)
來解決這個問題,每個使用者都屬于一個角色,每個角色都有其特定的權限,這樣新增使用者的時候,隻需要給他指派一個角色,他就可以擁有該角色對應的權限資訊。
使用
RBAC
模型需要在
ACL
MODEL的基礎上添加
role_definition
子產品:
g = _,_
定義了使用者——角色,角色——角色的映射關系,前者是後者的成員,擁有後者的權限。然後在比對器中,我們不需要判斷
r.sub
與
p.sub
是否相當,隻需要使用
g(r.sub, p.sub)
來判斷請求主體
r.sub
是否屬于
p.sub
這個角色即可。
[role_definition]
g = _, _
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
最後再修改政策檔案,下面的檔案就規定了
dajun
屬于
admin
管理者,
lizi
屬于
developer
開發者,使用
g
來定義這層關系。
另外具體的角色,如
admin
對資料data有rede和write權限也通過
p
來定義。
p, admin, data, read
p, admin, data, write
p, developer, data, read
g, dajun, admin
g, lizi, developer
我們編寫主程式
package main
import (
"fmt"
"log"
"github.com/casbin/casbin/v2"
)
func check(e *casbin.Enforcer, sub, obj, act string) {
ok, _ := e.Enforce(sub, obj, act)
if ok {
fmt.Printf("%s CAN %s %s\n", sub, act, obj)
} else {
fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
}
}
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "data", "read")
check(e, "dajun", "data", "write")
check(e, "lizi", "data", "read")
check(e, "lizi", "data", "write")
}
結果:
dajun CAN read data
dajun CAN write data
lizi CAN read data
lizi CANNOT write data
多個RBAC
可以為使用者和資源都賦予角色的概念
[role_definition]
g=_,_
g2=_,_
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act
上面的模型檔案定義了兩個
RBAC
系統
g
和
g2
,我們在比對器中使用
g(r.sub, p.sub)
判斷請求主體屬于特定組,
g2(r.obj, p.obj)
判斷請求資源屬于特定組,且操作一緻即可放行。
p, admin, prod, read
p, admin, prod, write
p, admin, dev, read
p, admin, dev, write
p, developer, dev, read
p, developer, dev, write
p, developer, prod, read
g, dajun, admin
g, lizi, developer
g2, prod.data, prod
g2, dev.data, dev
先看角色關系,即最後 4 行,
dajun
屬于
admin
角色,
lizi
屬于
developer
角色,
prod.data
屬于生産資源
prod
角色,
dev.data
屬于開發資源
dev
角色。
admin
角色擁有對
prod
和
dev
類資源的讀寫權限,
developer
隻能擁有對
dev
的讀寫權限和
prod
的讀權限。
check(e, "dajun", "prod.data", "read")
check(e, "dajun", "prod.data", "write")
check(e, "lizi", "dev.data", "read")
check(e, "lizi", "dev.data", "write")
check(e, "lizi", "prod.data", "write")
dajun CAN read prod.data
dajun CAN write prod.data
lizi CAN read dev.data
lizi CAN write dev.data
lizi CANNOT write prod.data
多層角色
可以為角色定義所屬角色,這種權限關系可以進行傳遞。
例如
dajun
屬于進階開發者
senior
,
seinor
屬于開發者,那麼
dajun
也是開發者,擁有開發者的所有權限,那麼我們就可以定義開發者共有的權限,然後額外為進階開發者
senior
定義一些特殊的權限。
模型檔案不需要修改,政策檔案改動如下:
# 定義了senior對資料data有write權限
p, senior, data, write
# 定義了developer對資料data有read權限
p, developer, data, read
# 為dajun賦予senior權限
g, dajun, senior
# 為senior賦予developer權限,senior權限本身對data有write權限,又被加了一個developer權限,就可寫可讀了。
g, senior, developer
# 為lizi賦予developer權限
g, lizi, developer
RBAC domain
角色可以是全局的,也可以是特定域(domain)的或租戶(tenant),可以了解為
組
。
例如
dajun
在組
tenant1
中是管理者,擁有很高的權限,但是在
tenant2
中可能隻是一個底層人員。
使用
RBAC domain
需要對模型檔案做以下修改:
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _,_,_
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.obj
g=_,_,_
表示前者在後者中擁有中間定義的角色,在比對器中使用
g
要帶上
dom
。
# admin在tenant1中對data1有read權限
p, admin, tenant1, data1, read
# admin在tenant2中對data2有read權限
p, admin, tenant2, data2, read
# dajun在tenant1中的角色是admin
g, dajun, admin, tenant1
# dajun在tenant2中的角色是developer
g, dajun, developer, tenant2
然後我們編寫主程式
func check(e *casbin.Enforcer, sub, domain, obj, act string) {
ok, _ := e.Enforce(sub, domain, obj, act)
if ok {
fmt.Printf("%s CAN %s %s in %s\n", sub, act, obj, domain)
} else {
fmt.Printf("%s CANNOT %s %s in %s\n", sub, act, obj, domain)
}
}
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "tenant1", "data1", "read")
check(e, "dajun", "tenant2", "data2", "read")
}
結果不出意料:
dajun CAN read data1 in tenant1
dajun CANNOT read data2 in tenant2
ABAC模型
RBAC
模型對于實作比較規則的、相對靜态的權限管理比較好用,但是例如我們需要在不同的時間段對資料
data
實作不同的權限控制,比如正常的工作時間
9:00-18:00
所有人都可以讀寫
data
,其它時間隻有資料所有者能讀寫。這種需求就需要使用
ABAC
模型完成。
首先修改
model
檔案:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[matchers]
m = r.sub.Hour >= 9 && r.sub.Hour < 18 || r.sub.Name == r.obj.Owner
[policy_effect]
e = some(where (p.eft == allow))
ABAC
模型不需要政策檔案:
type Object struct {
Name string
Owner string
}
type Subject struct {
Name string
Hour int
}
func check(e *casbin.Enforcer, sub Subject, obj Object, act string) {
ok, _ := e.Enforce(sub, obj, act)
if ok {
fmt.Printf("%s CAN %s %s at %d:00\n", sub.Name, act, obj.Name, sub.Hour)
} else {
fmt.Printf("%s CANNOT %s %s at %d:00\n", sub.Name, act, obj.Name, sub.Hour)
}
}
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
o := Object{"data", "dajun"}
s1 := Subject{"dajun", 10}
check(e, s1, o, "read")
s2 := Subject{"lizi", 10}
check(e, s2, o, "read")
s3 := Subject{"dajun", 20}
check(e, s3, o, "read")
s4 := Subject{"lizi", 20}
check(e, s4, o, "read")
}
dajun CAN read data at 10:00
lizi CAN read data at 10:00
dajun CAN read data at 20:00
lizi CANNOT read data at 20:00
使用
ABAC
模型可以非常靈活的進行權限控制,但是在一般情況的
RBAC
就夠用了。
模型存儲
casbin可以實作在代碼中動态初始化模型:
func main() {
m := model.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("e", "e", "some(where (p.eft == allow))")
m.AddDef("m", "m", "r.sub == g.sub && r.obj == p.obj && r.act == p.act")
a := fileadapter.NewAdapter("./policy.csv")
e, err := casbin.NewEnforcer(m, a)
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
或者在字元串中加載
func main() {
text := `
[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
`
m, _ := model.NewModelFromString(text)
a := fileadapter.NewAdapter("./policy.csv")
e, _ := casbin.NewEnforcer(m, a)
check(e, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
但是這兩種方式都不推薦使用
政策存儲
在前面的例子中,我們都是将政策存儲在一個.csv檔案中,但是實際應用中一般不用這種方式存儲,
casbin
以第三方擴充卡的方式支援多種存儲方式,包括
Mysql/MongoDB/Redis/Etcd
等。
CREATE DATABASE IF NOT EXISTS casbin;
USE casbin;
CREATE TABLE IF NOT EXISTS casbin_rule (
p_type VARCHAR(100) NOT NULL,
v0 VARCHAR(100),
v1 VARCHAR(100),
v2 VARCHAR(100),
v3 VARCHAR(100),
v4 VARCHAR(100),
v5 VARCHAR(100)
);
INSERT INTO casbin_rule VALUES
('p', 'dajun', 'data1', 'read', '', '', ''),
('p', 'lizi', 'data2', 'write', '', '', '');
然後使用
Gorm Adapter
加載
policy
,
Gorm Adapter
預設使用
casbin
庫中的
casbin_rule
表:
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v2"
_ "github.com/go-sql-driver/mysql"
)
func check(e *casbin.Enforcer, sub, obj, act string) {
ok, _ := e.Enforce(sub, obj, act)
if ok {
fmt.Printf("%s CAN %s %s\n", sub, act, obj)
} else {
fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
}
}
func main() {
a, _ := gormadapter.NewAdapter("mysql", "root:[email protected](127.0.0.1:3306)/")
e, _ := casbin.NewEnforcer("./model.conf", a)
check(e, "dajun", "data1", "read")
check(e, "lizi", "data2", "write")
check(e, "dajun", "data1", "write")
check(e, "dajun", "data2", "read")
}
運作:
dajun CAN read data1
lizi CAN write data2
dajun CANNOT write data1
dajun CANNOT read data2
使用函數
我們可以在比對器中使用函數。
casbin
内置了一些函數
keyMatch/keyMatch2/keyMatch3/keyMatch4
都是比對 URL 路徑的,
regexMatch
使用正則比對,
ipMatch
比對 IP 位址。參見https://casbin.org/docs/en/function。使用内置函數我們能很容易對路由進行權限劃分:
[matchers]
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && r.act == p.act
p, dajun, user/dajun/*, read
p, lizi, user/lizi/*, read
不同使用者隻能通路其對應路由下的 URL:
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%v\n", err)
}
check(e, "dajun", "user/dajun/1", "read")
check(e, "lizi", "user/lizi/2", "read")
check(e, "dajun", "user/lizi/1", "read")
}
輸出:
dajun CAN read user/dajun/1
lizi CAN read user/lizi/2
dajun CANNOT read user/lizi/1
我們當然也可以定義自己的函數。先定義一個函數,傳回 bool:
func KeyMatch(key1, 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{}
類型包裝一層:
func KeyMatchFunc(args ...interface{}) (interface{}, error) {
name1 := args[0].(string)
name2 := args[1].(string)
return (bool)(KeyMatch(name1, name2)), nil
}
然後添加到權限認證器中:
e.AddFunction("my_func", KeyMatchFunc)
這樣我們就可以在比對器中使用該函數實作正則比對了:
[matchers]
m = r.sub == p.sub && my_func(r.obj, p.obj) && r.act == p.act
接下來我們在政策檔案中為
dajun
賦予權限:
p, dajun, data/*, read
dajun
對比對模式
data/*
的檔案都有
read
權限。
驗證一下:
check(e, "dajun", "data/1", "read")
check(e, "dajun", "data/2", "read")
check(e, "dajun", "data/1", "write")
check(e, "dajun", "mydata", "read")
dajun
對
data/1
沒有
write
權限,
mydata
不符合
data/*
模式,也沒有
read
權限:
dajun CAN read data/1
dajun CAN read data/2
dajun CANNOT write data/1
dajun CANNOT read mydata
參考資料
- casbin中文開發文檔(官方)
- 每日一庫——casbin
歡迎評論區讨論,或指出問題。 如果覺得寫的不錯,歡迎點贊,轉發,收藏。