godoc
casbin官网
基础知识
Casbin 是一个强大和高效的开放源码访问控制库,它支持各种 访问控制模型 以强制全面执行授权。
开始使用
新建一个Casbin enforcer
Casbin使用配置文件来设置访问控制模型(Enforcer), model.conf 存储了我们的访问模型( Model),policy.csv 存储的是我们具体的用户权限配置(Adapter)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
// 使用MySQL数据库初始化一个Xorm适配器,Adapter
a, err := xormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/casbin")
if err != nil {
log.Fatalf("error: adapter: %s", err)
}
//Model
m, err := model.NewModelFromString(`
[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
`)
if err != nil {
log.Fatalf("error: model: %s", err)
}
//Enforcer
e, err := casbin.NewEnforcer(m, a)
if err != nil {
log.Fatalf("error: enforcer: %s", err)
}
|
也可以使用文件
1
|
e, err := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")
|
检查权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
sub := "alice" // 想要访问资源的用户。
obj: = "data1" // 将被访问的资源。
act := "read" // 用户对资源执行的操作。
ok, err := e.Enforce(sub, obj, act)
if err != nil {
// 处理err
}
if ok == true {
// 允许alice读取data1
} else {
// 拒绝请求,抛出异常
}
|
批量,返回slice
1
|
results, err := e.BatchEnforce([[] []interface{}{"alice", "data1", "read"}, {"bob", datata2", "write"}, {"jack", "data3", "read"}})
|
获得分配给一个用户的所有角色
1
|
roles, err := e.GetRolesForUser("alice")
|
访问控制模型
Model 的语法(PERM)
Request定义
[request_definition] 定义了 e.Enforce(…) 函数中的参数
[request_definition]
r = sub, obj, act
Policy定义
[policy_definition]是策略的定义,与Request的定义没有关系,相当于adapter中的条目的形参
[policy_definition]
p = sub, obj, act
p2 = sub, act
策略对应的adapter内容,有一个eft字段,该字段省略时默认为allow,在adapter里面只能定义为allow和deny
匹配器
[matchers] 是策略匹配器的定义
将r与policy里面的条目匹配,当一个条目p匹配的时候返回p.eft给effect。
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
匹配器中,可以使用算术运算符如 +, -, * , / ,也可以使用逻辑运算符如:&&,||,!
Policy effect定义
[policy_effect]部分是对policy生效范围的定义
[policy_effect]
e = some(where (p.eft == allow))
如果e为真则返回true给enforcer
函数
match内置函数
自定义函数签名,接收字符串返回bool
1
|
func KeyMatchFunc(args ...interface{}) (interface{}, error)
|
enforcer中注册函数
1
|
e.AddFunction("my_func", KeyMatchFunc)
|
match部分使用函数
[matchers]
m = r.sub == p.sub && my_func(r.obj, p.obj) && r.act == p.act
RBAC
[role_definition]
g = _, _ # 角色或资源
在match中使用的函数
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
g(r.sub, p.sub)会被翻译为r.sub==p.sub||gg(r.sub)==p.sub其中gg(r.sub)的结果是g条目中的第二个数据
[role_definition]
g = _, _, _ # 多商户
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
g(r.sub, p.sub, r.dom)会被翻译为r.sub==p.sub||gg(r.sub,r.dom)==p.sub其中gg(r.sub,r.dom)的结果是g条目中的第二个数据
存储
Model 的存储
model 不是动态组件,不应该在运行时进行修改,没有save API
从 .CONF 文件中加载 model
1
|
e := casbin.NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
|
从代码加载 model
1
2
3
4
5
6
7
|
// 从Go代码初始化模型
m := model.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("g", "g", "_, _")
m.AddDef("e", "e", "some(where (p.eft == allow))")
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act")
|
从字符串加载的 model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
text :=
`
[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
`
m, _ := model.NewModelFromString(text)
|
Policy的存储
从 CSV 文件载入策略
p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
适配器 API
见官网
- LoadPolicy()
- SavePolicy()
- AddPolicy()
- RemovePolicy()
- RemoveFilteredPolicy()
数据库存储格式
id ptype v0 v1 v2 v3 v4 v5
见官网