目 录CONTENT

文章目录
Go

Golang中使用casbin

Hello!你好!我是村望~!
2023-06-09 / 0 评论 / 2 点赞 / 108 阅读 / 1,276 字
温馨提示:
我不想探寻任何东西的意义,我只享受当下思考的快乐~

首先安装

go get github.com/casbin/casbin/v2

文件模式使用

Casbin使用配置文件来设置访问控制模型

它有两个配置文件, model.confpolicy.csv

  • 其中, model.conf 存储了我们的访问模型,

  • policy.csv 存储的是我们具体的用户权限配置。

Casbin 的使用非常精炼。 基本上,我们只需要一种主要的结构:enforcer 当构造这个结构的时候, model.confpolicy.csv 将会被加载。

model.conf

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

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

# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

policy.csv

p, alice, data1, read
p, bob, data2, write

Main.go

package main

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

func main() {
	e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
	if err != nil {
		log.Fatal(err)
	}
	sub1 := "alice"
	obj1 := "data2"
	act1 := "read"
	ok, err := e.Enforce(sub1, obj1, act1)
	if err != nil {
		fmt.Println(err)
	}
	if ok {
		fmt.Println(sub1, "通过!")
	} else {
		fmt.Println(sub1, "不通过")
	}
	sub2 := "bob"
	obj2 := "data2"
	act2 := "write"
	ok2, err := e.Enforce(sub2, obj2, act2)
	if err != nil {
		fmt.Println(err)
	}
	if ok2 {
		fmt.Println(sub2, "通过!")
	} else {
		fmt.Println(sub2, "不通过")
	}
}

➜  casbin go run main.go
alice 不通过
bob 通过!

数据库中使用Casbin

这里使用的是casbin提供的适配器

https://casbin.org/zh/docs/adapters

我使用的是gorm的adapter https://github.com/casbin/gorm-adapter

Gorm Adapter 是 Casbin 的 Gorm 适配器。有了这个库,Casbin 可以从 Gorm 支持的数据库加载策略或将策略保存到它。

INSTALL:

go get github.com/casbin/gorm-adapter/v3

基于官方支持的数据库,目前支持的数据库有:

  • MySQL
  • PostgreSQL 数据库
  • SQL Server 数据库服务器
  • Sqlite3

这里我们在本地使用 docker 启动一个本地的数据库

docker run -d --name mysql_container -e MYSQL_ROOT_PASSWORD=123 -p 3306:3306 mysql:latest

创建一个 casbin_db 用来测试

package main

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

func main() {
	// Initialize a Gorm adapter and use it in a Casbin enforcer:
	// The adapter will use the MySQL database named "casbin".
	// If it doesn't exist, the adapter will create it automatically.
	// You can also use an already existing gorm instance with gormadapter.NewAdapterByDB(gormInstance)
	a, _ := gormadapter.NewAdapter("mysql", "root:123@tcp(127.0.0.1:3306)/casbin_db", true) // Your driver and data source.
	e, _ := casbin.NewEnforcer("./model.conf", a)

	// Or you can use an existing DB "abc" like this:
	// The adapter will use the table named "casbin_rule".
	// If it doesn't exist, the adapter will create it automatically.
	// a := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/abc", true)
	added, _ := e.AddPolicy("alice", "data1", "read")
	fmt.Println("添加新的policy!", added)
	// Load the policy from DB.
	_ = e.LoadPolicy()

	// Check the permission.
	enforce, err := e.Enforce("alice", "data1", "read")
	if err != nil {
		log.Fatal(err.Error())
	}
	fmt.Println("校验结果", enforce)
	// Modify the policy.
	// e.AddPolicy(...)
	// e.RemovePolicy(...)

	// Save the policy back to DB.
	_ = e.SavePolicy()
}

这里如果数据表不存在的话,会报错!gormadapter.NewAdapter 传入一个true,表示适配器自动帮你创建表! named "casbin_rule".

image-20230609120302839

可以看到将policy 同步到了数据库中!并且 同步的Enforce校验就通过了!

而且他内部自动会帮我们查询是不是有重复的policy!如果有add就返回false (下图展示了第二次执行的结果!)

image-20230609141119163

数据库中casbin的CRUD

看文档就行

https://casbin.org/zh/docs/management-api

自定义Mathers 函数

https://casbin.org/zh/docs/function#matchers中的函数

本身内部就有很多内置函数!

我们可以这里重点是看如何自定义函数

首先准备您的函数。 它接受一些参数,然后返回一个布尔类型:我们自定义用在obj资源对象的判断只要为data1 就放过!

func KeyMatch(key1 string, key2 string) bool {
	fmt.Println(key1, key2)
	return key1 == "data1"
}

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

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

    return (bool)(KeyMatch(name1, name2)), nil
}

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

e.AddFunction("KeyMatchFunc", KeyMatchFunc)

现在,您可以在您的模型CONF中像这样使用这个函数:

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

完整代码

package main

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

func KeyMatch(key1 string, key2 string) bool {
	return key1 == "data1"
}
func KeyMatchFunc(args ...interface{}) (interface{}, error) {
	name1 := args[0].(string)
	name2 := args[1].(string)
	return (bool)(KeyMatch(name1, name2)), nil
}
func main() {
	a, _ := gormadapter.NewAdapter("mysql", "root:123@tcp(127.0.0.1:3306)/casbin_db", true) // Your driver and data source.
	e, _ := casbin.NewEnforcer("./model.conf", a)
	e.AddFunction("KeyMatchFunc", KeyMatchFunc)
	_ = e.LoadPolicy()

	enforce, err := e.Enforce("alice", "data1", "write")
	if err != nil {
		log.Fatal(err.Error())
	}
	fmt.Println("校验结果", enforce)
	_ = e.SavePolicy()
}

Model.conf

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

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

# Matchers
[matchers]
m = r.sub == p.sub && KeyMatchFunc(r.obj,p.obj) && r.act == p.act

image-20230609150711222

2

评论区