Contents

go第三方库-github.com.casbin.casbin

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

官网

 |