- casbin快速入门
- 下载依赖
- model文件(model.conf)
- policy文件(policy.csv)
- 代码实现
- 超级管理员实现
- g = _, _的用法
- 多个g _ , _
- 多层角色
- domain领域
- 动态控制可读可写
- 根据时间控制
- 模式存储
- 动态初始化model文件(代码内实现model)
- 策略储存policy.csv实际运用
casbin将访问控制模型抽象到一个基于 PERM(Policy,Effect,Request,Matchers) 元模型的配置文件(模型文件)中
-
policy是策略或者说是规则的定义。它定义了具体的规则。
-
request是对访问请求的抽象,它与e.Enforce()函数的参数是一一对应的
-
matcher匹配器会将请求与定义的每个policy一一匹配,生成多个匹配结果。
-
effect根据对请求运用匹配器得出的所有结果进行汇总,来决定该请求是允许还是拒绝。
model文件(model.conf)下载依赖
go get github.com/casbin/casbin/v2
# 请求定义 [request_definiation] r = sub,obj,act # sub ——> 想要访问资源的用户角色(Subject)——请求实体 # obj ——> 访问的资源(Object) # act ——> 访问的方法(Action: get、post...) # 策略定义 # 策略(.csv文件p的格式,定义的每一行为policy rule;p,p2为policy rule的名字。) [policy_definiation] p = sub,obj,act # p2 = sub,act 表示sub对所有资源都能执行act # 组定义 [role_definiation] g = _, _ # g = _,_定义了用户——角色,角色——角色的映射关系,前者是后者的成员,拥有后者的权限。 # _,_表示用户,角色/用户组 # 策略效果 [policy_effect] e = some(where(p.eft = allow)) # 上面表示有任意一条 policy rule 满足, 则最终结果为 allow;p.eft它可以是allow或deny,它是可选的,默认是allow # 匹配器 [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act # 上面模型文件规定了权限由sub,obj,act三要素组成,只有在策略列表中有和它完全相同的策略时,该请求才能通过。policy文件(policy.csv)
p,zxp,data1,read p,zhang,data2,write代码实现
package main
import (
"fmt"
"log"
"github.com/casbin/casbin/v2"
)
func check(e *casbin.Enforcer,sub,obj,act string){
ok,_ := e.Enforcer(sub,obj,act)
if ok {
fmt.Printf("%s CAN %s %sn", sub, act, obj)
} else {
fmt.Printf("%s CANNOT %s %sn", sub, act, obj)
}
}
func main() {
//首先创建一个casbin.Enforcer对象,加载模型文件model.conf和策略文件policy.csv,调用其 Enforce方法来检查权限
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%vn", err)
}
check(e, "zxp", "data1", "read")
check(e, "zhang", "data2", "write")
check(e, "zxp", "data1", "write")
check(e, "zxp", "data2", "read")
测试结果:
zxp CAN read data1 zhang CAN write data2 zxp CANNOT write data1 zxp CANNOT read data2超级管理员实现
[matchers] e = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"g = _, _的用法
g = _,__定义了用户——角色或角色——角色的映射关系,前者是后者的成员,拥有后者的权限。
model文件配置为
[matchers] m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
policy文件配置为
p, admin, data, read p, admin, data, write p, developer, data, read g, zxp, admin g, zhang, developer
admin对数据data用read和write权限,而developer对数据data只有read权限。
zxp拥有admin的权限所以可读可写 zhang只能读
多个g _ , _model文件配置改为:
[role_definition] g=_,_ g2=_,_ [matchers] m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act # 只改这两个,其他不变
policy文件举例如下:
p, admin, data1, read p, admin, data1, write p, admin, data2, read p, admin, data2, write p, developer, data2, read p, developer, data2, write p, developer, data1, read g, zxp, admin g, zhang, developer g2, data1.data, data1 g2, data2.data, data2
zxp属于admin所以对data1,data2可读可写
zhang属于developer所以对data1可读。对data2可读可写
data1.data属于data1,所以zxp可读可写,zhang对data1.data可读
data2.data属于data2,所以zhang可读可写
多层角色model文件不用修改
policy文件举例如下:
p, senior, data, write p, developer, data, read g, zxp, senior g, senior, developer g, zhang, developer
senior对data有write权限
developer只有read权限,同时senior也是developer(前者拥有后者的权限),所以senior也继承其read权限。
zxp可读可写data
zhang可读data
domain领域model文件修改如下
[request_definition] r = sub, dom, obj, act [policy_definition] p = sub, dom, obj, act [role_definition] g = _,_,_ # g2 = _,_,_ 表示用户, 角色/用户组, 域(也就是租户) [matchers] m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
policy文件举例如下:
p, admin, dom1, data1, read p, admin, dom2, data2, read g, zxp, admin, dom1
在dom1中,只有admin可以读取数据data1。
在dom2中,只有admin可以读取数据data2。
zxp在data1中是admin,但是在data2中不是。
代码实现
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 %sn", sub, act, obj, domain)
} else {
fmt.Printf("%s CANNOT %s %s in %sn", sub, act, obj, domain)
}
}
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%vn", err)
}
check(e, "dajun", "dom1", "data1", "read")
check(e, "dajun", "dom2", "data2", "read")
}
动态控制可读可写
根据时间控制
model文件修改如下
[matchers] m = r.sub.Hour >= 5 && r.sub.Hour < 20 || r.sub.Name == r.obj.Owner>
注意:该模式下不需要policy文件配置
代码实现
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:00n", sub.Name, act, obj.Name, sub.Hour)
} else {
fmt.Printf("%s CANNOT %s %s at %d:00n", sub.Name, act, obj.Name, sub.Hour)
}
}
func main() {
e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
if err != nil {
log.Fatalf("NewEnforecer failed:%vn", err)
}
//r.sub.Hour < 18 || r.sub.Name == r.obj.Owner 这两个满足一个就可读
o := Object{"data", "zxp"}
s1 := Subject{"zxp", 10}
check(e, s1, o, "read")//可读
s2 := Subject{"zhang", 10}
check(e, s2, o, "read")//可读
s4 := Subject{"zhang", 20}
check(e, s4, o, "read")//不可读
模式存储
动态初始化model文件(代码内实现model)
func check(e *casbin.Enforcer,sub,obj,act string){
ok,_ := e.Enforcer(sub,obj,act)
if ok {
fmt.Printf("%s CAN %s %sn", sub, act, obj)
} else {
fmt.Printf("%s CANNOT %s %sn", sub, act, obj)
}
}
//第一种写法
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:%vn", err)
}
check(e, "zxp", "data1", "read")
check(e, "zhang", "data2", "write")
check(e, "zxp", "data1", "write")
check(e, "zxp", "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)
}
策略储存policy.csv实际运用
使用Gorm Adapter。先连接到数据库,执行下面的SQL:
CREATE DATABASE IF NOT EXISTS casbin;
USE casbin;
CREATE TABLE IF NOT EXISTS casbin_rule (
p_type VARCHAr(100) NOT NULL,
s0 VARCHAr(100),
s1 VARCHAr(100),
s2 VARCHAr(100)
);
INSERT INTO casbin_rule VALUES
('p', zxp', 'data1', 'read', '', '', ''),
('p', 'zhang', 'data2', 'write', '', '', '');
代码实现
func check(e *casbin.Enforcer, sub, obj, act string) {
ok, _ := e.Enforce(sub, obj, act)
if ok {
fmt.Printf("%s CAN %s %sn", sub, act, obj)
} else {
fmt.Printf("%s CANNOT %s %sn", sub, act, obj)
}
}
func main() {
a, _ := gormadapter.NewAdapter("mysql", "root:12345@tcp(127.0.0.1:3306)/")
e, _ := casbin.NewEnforcer("./model.conf", a)
check(e, "zxp", "data1", "read")//可读
check(e, "zhang", "data2", "write")//可写
}



