跳转到主要内容

适配器(Adapter)

Casbin 通过 adapter(适配器) 加载和保存 policy。enforcer 会调用 LoadPolicy() 来加载规则,并在支持时调用 SavePolicy() 将其持久化。Adapter 被实现在独立的包中,以保持核心库足够精简。

支持的 adapter​

下面按语言列出了各个 adapter。要添加第三方 adapter,请提交 issue 或 PR。

Adapter Type Author AutoSave Description
File Adapter (built-in) File Casbin ❌ For .CSV (Comma-Separated Values) files
Filtered File Adapter (built-in) File @faceless-saint ❌ For .CSV (Comma-Separated Values) files with policy subset loading support
SQL Adapter SQL @Blank-Xu ✅ MySQL, PostgreSQL, SQL Server, SQLite3 are supported in master branch and Oracle is supported in oracle branch by database/sql
Xorm Adapter ORM Casbin ✅ MySQL, PostgreSQL, TiDB, SQLite, SQL Server, Oracle are supported by Xorm
GORM Adapter ORM Casbin ✅ MySQL, PostgreSQL, Sqlite3, SQL Server are supported by GORM
GORM Adapter Ex ORM Casbin ✅ MySQL, PostgreSQL, Sqlite3, SQL Server are supported by GORM
Ent Adapter ORM Casbin ✅ MySQL, MariaDB, PostgreSQL, SQLite, Gremlin-based graph databases are supported by ent ORM
Beego ORM Adapter ORM Casbin ✅ MySQL, PostgreSQL, Sqlite3 are supported by Beego ORM
SQLX Adapter ORM @memwey ✅ MySQL, PostgreSQL, SQLite, Oracle are supported by SQLX
Sqlx Adapter ORM @Blank-Xu ✅ MySQL, PostgreSQL, SQL Server, SQLite3 are supported in master branch and Oracle is supported in oracle branch by sqlx
GF ORM Adapter ORM @vance-liu ✅ MySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
GoFrame ORM Adapter ORM @kotlin2018 ✅ MySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
gf-adapter ORM @zcyc ✅ MySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
Gdb Adapter ORM @jxo-me ✅ MySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
GoFrame V2 Adapter ORM @hailaz ✅ MySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
Bun Adapter ORM @JunNishimura ✅ MySQL, SQLite, PostgreSQL, SQL Server are supported by Bun ORM
Filtered PostgreSQL Adapter SQL Casbin ✅ For PostgreSQL
Filtered pgx Adapter SQL @pckhoi ✅ PostgreSQL is supported by pgx
Pgx Adapter SQL @gtoxlili ✅ PostgreSQL is supported by pgx, supports customizable column count
casbin-pgx-adapter SQL @noho-digital ✅ A PostgreSQL adapter for Casbin using the pgx driver.
PostgreSQL Adapter SQL @cychiuae ✅ For PostgreSQL
RQLite Adapter SQL EDOMO Systems ✅ For RQLite
MongoDB Adapter NoSQL Casbin ✅ For MongoDB based on MongoDB Go Driver
RethinkDB Adapter NoSQL @adityapandey9 ✅ For RethinkDB
Cassandra Adapter NoSQL Casbin ❌ For Apache Cassandra DB
DynamoDB Adapter NoSQL HOOQ ❌ For Amazon DynamoDB
Dynacasbin NoSQL NewbMiao ✅ For Amazon DynamoDB
ArangoDB Adapter NoSQL @adamwasila ✅ For ArangoDB
Amazon S3 Adapter Cloud Soluto ❌ For Minio and Amazon S3
Go CDK Adapter Cloud @bartventer ✅ Adapter based on Go Cloud Dev Kit that supports: Amazon DynamoDB, Azure CosmosDB, GCP Firestore, MongoDB, In-Memory
Azure Cosmos DB Adapter Cloud @spacycoder ✅ For Microsoft Azure Cosmos DB
GCP Firestore Adapter Cloud @reedom ❌ For Google Cloud Platform Firestore
GCP Cloud Storage Adapter Cloud qurami ❌ For Google Cloud Platform Cloud Storage
GCP Cloud Spanner Adapter Cloud @flowerinthenight ✅ For Google Cloud Platform Cloud Spanner
Consul Adapter KV store @ankitm123 ❌ For HashiCorp Consul
Redis Adapter (Redigo) KV store Casbin ✅ For Redis
Redis Adapter (go-redis) KV store @mlsen ✅ For Redis
Etcd Adapter KV store @sebastianliu ❌ For etcd
BoltDB Adapter KV store @speza ✅ For Bolt
Bolt Adapter KV store @wirepair ❌ For Bolt
BadgerDB Adapter KV store @inits ✅ For BadgerDB
Protobuf Adapter Stream Casbin ❌ For Google Protocol Buffers
JSON Adapter String Casbin ❌ For JSON
String Adapter String @qiangmzsx ❌ For String
HTTP File Adapter HTTP @h4ckedneko ❌ For http.FileSystem
FileSystem Adapter File @naucon ❌ For fs.FS and embed.FS
NATS JetStream Adapter KV store grepplabs ✅ For NATS JetStream
Kubernetes Adapter Cloud grepplabs ✅ For Kubernetes
备注
  1. 当你(显式或隐式地)把 adapter 传给 casbin.NewEnforcer() 时,policy 会自动加载。
  2. 调用 e.LoadPolicy() 可以从存储中刷新 policy。
  3. 在没有 Auto-Save 支持的情况下,当你修改 policy 时,adapter 无法自动持久化这些变更。请手动调用 SavePolicy() 来保存所有规则。

示例​

下面是一些 adapter 的使用示例:

文件 adapter(内置)​

使用内置的文件 adapter 初始化一个 enforcer:

import "github.com/casbin/casbin/v3"

e := casbin.NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")

等价的另一种写法:

import (
"github.com/casbin/casbin/v3"
fileadapter "github.com/casbin/casbin/v3/persist/file-adapter"
)

a := fileadapter.NewAdapter("examples/basic_policy.csv")
e := casbin.NewEnforcer("examples/basic_model.conf", a)

MySQL adapter​

使用 MySQL 数据库连接(127.0.0.1:3306,root 用户,无密码)初始化一个 enforcer:

import (
"github.com/casbin/casbin/v3"
"github.com/casbin/mysql-adapter"
)

a := mysqladapter.NewAdapter("mysql", "root:@tcp(127.0.0.1:3306)/")
e := casbin.NewEnforcer("examples/basic_model.conf", a)

使用你自己的存储 adapter​

集成一个自定义 adapter:

import (
"github.com/casbin/casbin/v3"
"github.com/your-username/your-repo"
)

a := yourpackage.NewAdapter(params)
e := casbin.NewEnforcer("examples/basic_model.conf", a)

在不同的 adapter 之间迁移/转换​

要把 policy 从 adapter A 迁移到 adapter B:

1.把 policy 从 A 加载到内存中

e, _ := NewEnforcer(m, A)

或者

e.SetAdapter(A)
e.LoadPolicy()

2.从 adapter A 切换到 B

e.SetAdapter(B)

3.把内存中的 policy 保存到 B

e.SavePolicy()

运行时加载/保存​

在初始化之后重新加载模型和 policy,或持久化 policy 的变更:

// Reload the model from the model CONF file.
e.LoadModel()

// Reload the policy from file/database.
e.LoadPolicy()

// Save the current policy (usually after changed with Casbin API) back to file/database.
e.SavePolicy()

AutoSave​

支持 Auto-Save 的 adapter 可以把单条 policy 的变更直接持久化到存储中,无需执行一次完整的保存操作。这与 SavePolicy() 不同,后者会清空存储并重写所有 policy,在 policy 数量较大时可能带来性能问题。

当某个 adapter 支持 Auto-Save 时,可以通过 Enforcer.EnableAutoSave() 来控制这一行为。对于兼容的 adapter,该选项默认是开启的。

备注
  1. Auto-Save 是一个可选功能。Adapter 可以实现它,也可以不实现。
  2. 只有当 enforcer 的 adapter 支持时,Auto-Save 才会生效。
  3. 可以通过上面 adapter 列表中的 AutoSave 一列来判断是否支持。

Auto-Save 使用示例:

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

// AutoSave is enabled by default when using compatible adapters with enforcers.
a := xormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")
e := casbin.NewEnforcer("examples/basic_model.conf", a)

// Disable AutoSave.
e.EnableAutoSave(false)

// Policy changes affect only the in-memory enforcer,
// not the storage.
e.AddPolicy(...)
e.RemovePolicy(...)

// Enable AutoSave.
e.EnableAutoSave(true)

// Policy changes now persist to storage
// in addition to updating the in-memory enforcer.
e.AddPolicy(...)
e.RemovePolicy(...)

更多示例:https://github.com/apache/casbin-xorm-adapter/blob/master/adapter_test.go

如何编写一个 adapter​

实现 Adapter 接口,至少包含两个必需的方法:LoadPolicy(model model.Model) error 和 SavePolicy(model model.Model) error。

另外三个可选方法用于支持 Auto-Save。

方法类型说明
LoadPolicy()mandatory从存储中加载所有 policy 规则
SavePolicy()mandatory把所有 policy 规则保存到存储中
AddPolicy()optional向存储中添加一条 policy 规则
RemovePolicy()optional从存储中删除一条 policy 规则
RemoveFilteredPolicy()optional从存储中删除与过滤器匹配的 policy 规则
备注

当一个 adapter 不支持 Auto-Save 时,请为这三个可选方法提供空的实现。Golang 示例:

// AddPolicy adds a policy rule to the storage.
func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error {
return errors.New("not implemented")
}

// RemovePolicy removes a policy rule from the storage.
func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error {
return errors.New("not implemented")
}

// RemoveFilteredPolicy removes policy rules that match the filter from the storage.
func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error {
return errors.New("not implemented")
}

Casbin 的 enforcer 在调用这些可选方法时会忽略 "not implemented" 错误。

Adapter 的实现要求:

  • 数据结构。至少支持读取 6 列。
  • 数据库名。默认为 casbin。
  • 表名。默认为 casbin_rule。
  • Ptype 列。命名为 ptype(而不是 p_type 或 Ptype)。
  • 表定义:(id int primary key, ptype varchar, v0 varchar, v1 varchar, v2 varchar, v3 varchar, v4 varchar, v5 varchar)。
  • 唯一键索引:建立在 ptype,v0,v1,v2,v3,v4,v5 这些列上。
  • LoadFilteredPolicy 接受一个如下结构的 filter 参数:
{
"p": ["", "domain1"],
"g": ["", "", "domain1"]
}

谁负责创建数据库?​

按照惯例,adapter 应该在 casbin 数据库不存在时自动创建它,并用它来存储 policy。参考实现:https://github.com/apache/casbin-xorm-adapter

Update Adapter​

UpdateAdapter 接口扩展了基本的 Adapter 接口,可以直接在存储中更新 policy。与"先删除再添加"相比,这种方式在修改已有规则时效率更高。

实现了 UpdateAdapter 的 adapter 提供以下方法:

方法类型说明
UpdatePolicy()optional在存储中更新一条 policy 规则
UpdatePolicies()optional在存储中更新多条 policy 规则
UpdateFilteredPolicies()optional在存储中更新与过滤器匹配的 policy 规则

示例​

Update adapter 的用法:

import (
"github.com/casbin/casbin/v3"
"github.com/casbin/gorm-adapter/v3"
)

a, _ := gormadapter.NewAdapter("mysql", "root:@tcp(127.0.0.1:3306)/")
e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a)

// Update a single policy
// Change: p, alice, data1, read -> p, alice, data1, write
e.UpdatePolicy(
[]string{"alice", "data1", "read"},
[]string{"alice", "data1", "write"},
)

// Update multiple policies at once
e.UpdatePolicies(
[][]string{{"alice", "data1", "write"}, {"bob", "data2", "read"}},
[][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}},
)

// Update all policies matching a filter
e.UpdateFilteredPolicies(
[][]string{{"alice", "data1", "write"}},
0,
"alice", "data1", "read",
)

如何编写一个 update adapter​

要实现 UpdateAdapter,请在你基本的 Adapter 实现基础上添加这些更新方法:

// UpdatePolicy updates a policy rule from storage.
// This is part of the UpdateAdapter interface.
func (a *Adapter) UpdatePolicy(sec string, ptype string, oldRule, newRule []string) error {
// Update the policy in storage
// SQL example: UPDATE casbin_rule SET v0=?, v1=?, v2=? WHERE ptype=? AND v0=? AND v1=? AND v2=?
return nil
}

// UpdatePolicies updates multiple policy rules in the storage.
// This is part of the UpdateAdapter interface.
func (a *Adapter) UpdatePolicies(sec string, ptype string, oldRules, newRules [][]string) error {
// Update multiple policies in storage
// Use transactions for consistency
return nil
}

// UpdateFilteredPolicies updates policy rules that match the filter from the storage.
// This is part of the UpdateAdapter interface.
func (a *Adapter) UpdateFilteredPolicies(sec string, ptype string, newRules [][]string, fieldIndex int, fieldValues ...string) error {
// Find policies matching the filter, then update them
return nil
}
备注

在不支持 UpdateAdapter 的情况下,Casbin 会自动回退为组合使用 RemovePolicy() 和 AddPolicy() 操作。

Context Adapter​

ContextAdapter 为 Casbin 的 adapter 提供了支持 context 的操作。

Context 可以用来实现诸如 adapter API 调用超时控制之类的特性。

示例​

gormadapter 支持 context。下面是使用 context 做超时控制的示例:

ca, _ := NewContextAdapter("mysql", "root:@tcp(127.0.0.1:3306)/", "casbin")
// Set 300s timeout
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond)
defer cancel()

err := ca.AddPolicyCtx(ctx, "p", "p", []string{"alice", "data1", "read"})
if err != nil {
panic(err)
}

如何编写一个 context adapter​

ContextAdapter API 在标准 Adapter API 之上增加了一层 context 处理。在实现标准 Adapter API 之后,再用 context 处理包装你的逻辑即可。

参考实现:adapter.go

Transaction​

Casbin 支持事务。gormadapter 中的事务用法:

db, _ := gorm.Open(...)
adapter, _ := gormadapter.NewTransactionalAdapterByDB(db)
e, _ := casbin.NewTransactionalEnforcer("examples/rbac_model.conf", adapter)

ctx := context.Background()

// WithTransaction executes a function within a transaction.
// Errors trigger rollback; otherwise, automatic commit occurs.
err := e.WithTransaction(ctx, func(tx *casbin.Transaction) error {
tx.AddPolicy("alice", "data1", "read")
tx.AddPolicy("alice", "data1", "write")
return nil
})

// Manual transaction handling
tx, _ := e.BeginTransaction(ctx)
tx.AddPolicy("alice", "data1", "write")
if err := tx.Commit(); err != nil {
// handle transaction failure
}

要实现事务支持,请实现 persist/transaction.go 中的 TransactionalAdapter 和 TransactionContext。

参考:adapter.go