簡(jiǎn)介
權(quán)限管理在幾乎每個(gè)系統(tǒng)中都是必備的模塊裂明。如果項(xiàng)目開(kāi)發(fā)每次都要實(shí)現(xiàn)一次權(quán)限管理,無(wú)疑會(huì)浪費(fèi)開(kāi)發(fā)時(shí)間太援,增加開(kāi)發(fā)成本闽晦。因此,casbin庫(kù)出現(xiàn)了提岔。casbin是一個(gè)強(qiáng)大仙蛉、高效的訪問(wèn)控制庫(kù)。支持常用的多種訪問(wèn)控制模型碱蒙,如ACL/RBAC/ABAC等荠瘪。可以實(shí)現(xiàn)靈活的訪問(wèn)權(quán)限控制赛惩。同時(shí)巧还,casbin支持多種編程語(yǔ)言,Go/Java/Node/PHP/Python/.NET/Rust.
安裝
go get github.com/casbin/casbin/v2
權(quán)限實(shí)際上就是控制誰(shuí)能對(duì)什么資源進(jìn)行什么操作坊秸。casbin將訪問(wèn)控制模型抽象到一個(gè)基于 PERM(Policy麸祷,Effect,Request褒搔,Matchers) 元模型的配置文件(模型文件)中阶牍。因此切換或更新授權(quán)機(jī)制只需要簡(jiǎn)單地修改配置文件喷面。
policy
是策略或者說(shuō)是規(guī)則的定義。它定義了具體的規(guī)則走孽。request
是對(duì)訪問(wèn)請(qǐng)求的抽象惧辈,它與e.Enforce()
函數(shù)的參數(shù)是一一對(duì)應(yīng)的matcher
匹配器會(huì)將請(qǐng)求與定義的每個(gè)policy
一一匹配,生成多個(gè)匹配結(jié)果磕瓷。effect
根據(jù)對(duì)請(qǐng)求運(yùn)用匹配器得出的所有結(jié)果進(jìn)行匯總盒齿,來(lái)決定該請(qǐng)求是允許還是拒絕。
模型文件 (model.conf)
[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))
上面模型文件規(guī)定了權(quán)限由sub,obj,act三要素組成困食,只有在策略列表中有和它完全相同的策略時(shí)边翁,該請(qǐng)求才能通過(guò)。匹配器的結(jié)果可以通過(guò)p.eft獲取硕盹,some(where (p.eft == allow))表示只要有一條策略允許即可符匾。
策略文件 (policy.csv)
p, person1, data1, read
p, person2, data2, write
上面的策略文件規(guī)定了person1對(duì)data1有read權(quán)限,而person2對(duì)data2有write權(quán)限
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, "person1", "data1", "read")
check(e, "person2", "data2", "write")
check(e, "person1", "data1", "write")
check(e, "person2", "data2", "read")
}
運(yùn)行結(jié)果
person1 CAN read data1
person2 CAN write data2
person1 CANNOT write data1
person1 CANNOT read data2
RBAC
RBAC(role-based-access-control)
模型通過(guò)引入角色(role)這個(gè)中間層來(lái)解決這個(gè)問(wèn)題。每個(gè)用戶都屬于一個(gè)角色瘩例,例如開(kāi)發(fā)者啊胶、管理員、運(yùn)維等垛贤,每個(gè)角色都有其特定的權(quán)限焰坪,權(quán)限的增加和刪除都通過(guò)角色來(lái)進(jìn)行。這樣新增一個(gè)用戶時(shí)聘惦,我們只需要給他指派一個(gè)角色某饰,他就能擁有該角色的所有權(quán)限。修改角色的權(quán)限時(shí)部凑,屬于這個(gè)角色的用戶權(quán)限就會(huì)相應(yīng)的修改露乏。
在model中定義
[role_definition]
g = _, _
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
g _ , _
表示前面的角色繼承后面的角色,并擁有后面角色的權(quán)限
示例
p, admin, data, read
p, admin, data, write
g, person, admin
person擁有的權(quán)限,對(duì)data有write和read權(quán)限
ABAC
- RBAC模型對(duì)于實(shí)現(xiàn)比較規(guī)則的、相對(duì)靜態(tài)的權(quán)限管理非常有用涂邀。
[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))
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")
}