当前位置: 首页 > 工具软件 > casbin > 使用案例 >

casbin学习笔记

章涵容
2023-12-01

安装

$ go get github.com/casbin/casbin/v2
import "github.com/casbin/casbin/v2"

func main() {
	e, err := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")
}

创建文件

在当前目录下创建model.confpolicy.csv文件,JetBrains有Casbin插件,如果装有该插件,model.conf图标会变

model.conf内装的就是模型,policy.csv装的就是policy(暂时先用csv装一下)

示例:

[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
p,zhangsan,data1,read

开始用

package main

import (
	"fmt"
	"github.com/casbin/casbin/v2"
)

func main() {
	e, err := casbin.NewEnforcer("model.conf", "policy.csv") // 模型与policy的路径

	sub := "alice" // 想要访问资源的用户。
	obj := "data1" // 将被访问的资源。
	act := "read"  // 用户对资源执行的操作。

	ok, err := e.Enforce(sub, obj, act) //Enforce决定一个 “subject” 是否能够用 “action” 操作访问 “object” 

	if err != nil {
        // 异常处理
		fmt.Println(err)
		return
	}

	if ok == true {
		// 允许alice读取data1
		fmt.Println("允许alice的操作")
	} else {
		// 拒绝请求,抛出异常
		fmt.Println("拒绝alice的操作")
	}
}

此时运行结果一定是

拒绝alice的操作

进程 已完成,退出代码为 0

因为alice没有在policy中给予任何权限

查询指定字段的policy

GetFilteredPolicy()

GetFilteredPolicy 获取策略中的所有授权规则,我们可以指定字段筛选器。

例如:

filteredPolicy := e.GetFilteredPolicy(0, "alice")
// 查询v0字段为alice的所有policy

v0字段:存放到数据库中的policy有这样几列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wq5VXp0-1651581293719)(casbin图片/image-20220503172422514.png)]

而v0字段就是sub字段

适配器

全部适配器

gorm 适配器

gorm适配器

直接把这玩意儿粘贴过去就行,这玩意儿就在github的readme里

import (
	"github.com/casbin/casbin/v2"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	_ "github.com/go-sql-driver/mysql"
)

func main(){
    // 初始化Gorm适配器并在Casbin enforcer中使用:
	// 适配器将使用名为“casbin”的MySQL数据库。
	// 如果它不存在,适配器将自动创建它。
	// 您还可以将已经存在的gorm实例与gormadapter一起使用。NewAdapterByDB(gormInstance)
	a, _ := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/") // 你的驱动程序和数据源。
	e, _ := casbin.NewEnforcer("./model.conf", a)
	// 或者您可以使用现有的数据库“abc”,如下所示:
	// 适配器将使用名为“casbin_rule”的表。
	// 如果它不存在,适配器将自动创建它。
	// a := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/abc", true)
	
    // 如果你的数据库中既没有名为casbin的数据库,也没有名为casbin_rule的表,那么直接用
    // a, _ := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")即可,它会自动创建
}


增删改查Policy

这里就先使用AddPolicy()来写增,其他的查API

// 增加一条Policy
addPolicy, err := e.AddPolicy("alice", "data2", "read") // 添加成功返回true,已存在返回false
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(addPolicy)

增加一个grouping

这一步一定要注意看自己的Model是否有,否则会报错

[role_definition]
g = _, _

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
// 增加一个grouping
added,err := e.AddGroupingPolicy("alice", "data1_admin")
fmt.Println(added)
fmt.Println(err)

RemovePolicy(),其他查api

removed, err := e.RemovePolicy("alice", "data2", "read")

删 groupingPolicy 用RemoveGroupingPolicy()

UpdatePolicy()改,其他查api

func (e *Enforcer) UpdatePolicy(oldPolicy []string, newPolicy []string) (bool, error)

// 例:
updated, err := e.UpdatePolicy([]string{"alice", "data1", "read"}, []string{"alice", "data2", "read"})

改groupingPolicy查api

policy := e.GetPolicy()
fmt.Println(policy)

自定义函数

首先自己写一个函数,返回一个布尔类型

// 随便写一个
func KeyMatch(key1 string, key2 string) bool {
    return key1 == key2
}

然后用interface{}类型的接口包装它

func KeyMatchFunc(args ...interface{}) (interface{},error){
    name1 := args[0].(string)
    name2 := args[1].(string)
    
    return (bool)(keyMatch(name1,name2)),nil
}

最后在casbin的执行者(enforcer)中注册这个函数

// 第一个参数是在模型中,这个自定义函数的名字
// 第二个参数是刚才用来包装的interface{}类型的接口
e.AddFunction("my_func",KeyMatchFunc)

最后便可在模型conf中使用这个函数

[matchers]
m = my_func(r.sub, p.sub) && r.obj == p.obj  && r.act == p.act

记了一点点的api

Casbin API

添加权限

AddPolicy()

AddPolicy 向当前策略添加授权规则。 如果规则已经存在,函数返回false,并且不会添加规则。 否则,函数通过添加新规则并返回true。

如果当前的policy是在本地的csv文件中存储,则这条policy不会添加进csv文件中

但在数据库中存储的话,这条policy会存进数据表中

added, err := e.AddPolicy('eve', 'data3', 'read')

查询所有policy

policy := e.GetPolicy()

PERM元模型

定义一个策略(Policy) 定义一个匹配规则(Matchers) 通过请求(Request)过来的参数与策略通过规则进行匹配获得一个影响(Effect),拿到影响的结果,进到影响的表达式,返回一个布尔值

PERM(Policy Effect Request Matchers)

  • subject: sub 访问实体

  • object: obj 访问的资源

  • action: act 访问方法

  • eft: eft 策略结果,一般为空,默认指定allow,还可以定义为deny(拒绝)(只有这两种结果)

Policy策略

一般存储到数据库

p = {sub, obj, act, eft}

[policy_definition]
p = sub,obj,act

Matchers 匹配规则

Request和Policy的匹配规则

m = r.sub == p.sub && r.act == p.act && r.obj == p.obj

Effect 影响

支持的Policy effects如下:

Policy effect意义
some(where (p.eft == allow))只要有一个allow就通过
!some(where (p.eft == deny))没有deny就通过
some(where (p.eft == allow)) && !some(where (p.eft == deny))有allow并且没有deny通过
priority(p.eft) || denypriority
subjectPriority(p.eft)基于角色的优先级

Request 请求

r = {sub, obj, act}

ACL

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act // 这里不加 ', eft'的话,police_effect就没有用到

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
p, alice, data1, read
p, bob, data2, write
alice, data1, read
true

RBAC

单商户模型

和ACL模型相比,多了一个[role_definition] g后面的两个横线,一个表示用户,一个表示角色,

在[matchers]中,也有了g(r.sub, p.sub)

[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
p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write

g, alice, data2_admin

Policy最后一行,用户alice有作为data2_admin角色,感觉就像是alice他有另一个马甲,叫做data2_admin,这两个都是它的身份,像一个人,他既是作为游戏开发者,也是作为玩家,这两个都是它的身份,而他既能行驶玩家的权限,游玩游戏,又能作为开发者,修改自己游戏的数据。

alice, data2, read
true

RBAC with domains/tenants

多商户模型

与单商户模型相比,又多了一个domains

在[request_definition],[policy_definition]中,都多出来了一个dom

[role_definition]多出一条横线

[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
p, admin, domain1, data1, read
p, admin, domain1, data1, write
p, admin, domain2, data2, read
p, admin, domain2, data2, write

g, alice, admin, domain1
g, bob, admin, domain2

对于domain(域)我的理解是,

像一个人,他是一个游戏玩家,还是一个游戏开发者,在电脑上(domain1),他可以行驶游戏角色的权利,对其他角色发起攻击,他也行驶游戏开发者的权利,修改自己角色数值。离开了电脑,到现实世界(domain2),他作为游戏玩家,什么都做不了,但作为游戏开发者,他有领取薪水的权利

alice, domain1, data1, read
true
 类似资料: