Zum Hauptinhalt springen

Adapters

In Casbin wird der Richtlinienspeicher als Adapter implementiert (auch bekannt als Middleware für Casbin). Ein Casbin-Benutzer kann einen Adapter verwenden, um Richtlinienregeln von einem Speicher zu laden (auch bekannt als LoadPolicy()), oder um Richtlinienregeln darin zu speichern (auch bekannt als SavePolicy()). Um leichtgewichtig zu bleiben, setzen wir den Adaptercode nicht in die Hauptbibliothek.

Unterstützte Adapter

Eine vollständige Liste der Casbin-Adapter finden Sie unten. Jeder Beitrag von Dritten zu einem neuen Adapter ist willkommen, bitte informieren Sie uns und wir werden ihn in diese Liste aufnehmen:

AdapterTypeAuthorAutoSaveDescription
File Adapter (built-in)FileCasbinFor .CSV (Comma-Separated Values) files
Filtered File Adapter (built-in)File@faceless-saintFor .CSV (Comma-Separated Values) files with policy subset loading support
SQL AdapterSQL@Blank-XuMySQL, PostgreSQL, SQL Server, SQLite3 are supported in master branch and Oracle is supported in oracle branch by database/sql
Xorm AdapterORMCasbinMySQL, PostgreSQL, TiDB, SQLite, SQL Server, Oracle are supported by Xorm
GORM AdapterORMCasbinMySQL, PostgreSQL, Sqlite3, SQL Server are supported by GORM
GORM Adapter ExORMCasbinMySQL, PostgreSQL, Sqlite3, SQL Server are supported by GORM
Ent AdapterORMCasbinMySQL, MariaDB, PostgreSQL, SQLite, Gremlin-based graph databases are supported by ent ORM
Beego ORM AdapterORMCasbinMySQL, PostgreSQL, Sqlite3 are supported by Beego ORM
SQLX AdapterORM@memweyMySQL, PostgreSQL, SQLite, Oracle are supported by SQLX
Sqlx AdapterORM@Blank-XuMySQL, PostgreSQL, SQL Server, SQLite3 are supported in master branch and Oracle is supported in oracle branch by sqlx
GF ORM AdapterORM@vance-liuMySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
GoFrame ORM AdapterORM@kotlin2018MySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
gf-adapterORM@zcycMySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
Gdb AdapterORM@jxo-meMySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
GoFrame V2 AdapterORM@hailazMySQL, SQLite, PostgreSQL, Oracle, SQL Server are supported by GoFrame ORM
Bun AdapterORM@JunNishimuraMySQL, SQLite, PostgreSQL, SQL Server are supported by Bun ORM
Filtered PostgreSQL AdapterSQLCasbinFor PostgreSQL
Filtered pgx AdapterSQL@pckhoiPostgreSQL is supported by pgx
Pgx AdapterSQL@gtoxliliPostgreSQL is supported by pgx, supports customizable column count
PostgreSQL AdapterSQL@cychiuaeFor PostgreSQL
RQLite AdapterSQLEDOMO SystemsFor RQLite
MongoDB AdapterNoSQLCasbinFor MongoDB based on MongoDB Go Driver
RethinkDB AdapterNoSQL@adityapandey9For RethinkDB
Cassandra AdapterNoSQLCasbinFor Apache Cassandra DB
DynamoDB AdapterNoSQLHOOQFor Amazon DynamoDB
DynacasbinNoSQLNewbMiaoFor Amazon DynamoDB
ArangoDB AdapterNoSQL@adamwasilaFor ArangoDB
Amazon S3 AdapterCloudSolutoFor Minio and Amazon S3
Go CDK AdapterCloud@bartventerAdapter based on Go Cloud Dev Kit that supports: Amazon DynamoDB, Azure CosmosDB, GCP Firestore, MongoDB, In-Memory
Azure Cosmos DB AdapterCloud@spacycoderFor Microsoft Azure Cosmos DB
GCP Firestore AdapterCloud@reedomFor Google Cloud Platform Firestore
GCP Cloud Storage AdapterCloudquramiFor Google Cloud Platform Cloud Storage
GCP Cloud Spanner AdapterCloud@flowerinthenightFor Google Cloud Platform Cloud Spanner
Consul AdapterKV store@ankitm123For HashiCorp Consul
Redis Adapter (Redigo)KV storeCasbinFor Redis
Redis Adapter (go-redis)KV store@mlsenFor Redis
Etcd AdapterKV store@sebastianliuFor etcd
BoltDB AdapterKV store@spezaFor Bolt
Bolt AdapterKV store@wirepairFor Bolt
BadgerDB AdapterKV store@initsFor BadgerDB
Protobuf AdapterStreamCasbinFor Google Protocol Buffers
JSON AdapterStringCasbinFor JSON
String AdapterString@qiangmzsxFor String
HTTP File AdapterHTTP@h4ckednekoFor http.FileSystem
FileSystem AdapterFile@nauconFor fs.FS and embed.FS
NATS JetStream AdapterKV storegrepplabsFor NATS JetStream
Kubernetes AdapterCloudgrepplabsFor Kubernetes
notiz
  1. Wenn casbin.NewEnforcer() mit einem expliziten oder impliziten Adapter aufgerufen wird, wird die Richtlinie automatisch geladen.
  2. Sie können e.LoadPolicy() aufrufen, um die Richtlinienregeln aus dem Speicher neu zu laden.
  3. Wenn der Adapter die Funktion Auto-Save nicht unterstützt, können die Richtlinienregeln nicht automatisch zurück in den Speicher gespeichert werden, wenn Sie Richtlinien hinzufügen oder entfernen. Sie müssen SavePolicy() manuell aufrufen, um alle Richtlinienregeln zu speichern.

Beispiele

Hier stellen wir einige Beispiele vor:

Dateiadapter (eingebaut)

Unten wird gezeigt, wie ein Durchsetzer vom eingebauten Dateiadapter initialisiert wird:

import "github.com/casbin/casbin"

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

Das ist das Gleiche wie:

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

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

MySQL-Adapter

Unten wird gezeigt, wie ein Durchsetzer von einer MySQL-Datenbank initialisiert wird. Es stellt eine Verbindung zu einer MySQL-DB auf 127.0.0.1:3306 mit root und leerem Passwort her.

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

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

Verwenden Sie Ihren eigenen Speicheradapter

Sie können Ihren eigenen Adapter wie folgt verwenden:

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

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

Migration/Konvertierung zwischen verschiedenen Adaptern

Wenn Sie den Adapter von A zu B konvertieren möchten, können Sie dies wie folgt tun:

  1. Laden Sie die Richtlinie von A in den Speicher
e, _ := NewEnforcer(m, A)

oder

e.SetAdapter(A)
e.LoadPolicy()
  1. Konvertieren Sie Ihren Adapter von A zu B
e.SetAdapter(B)
  1. Speichern Sie die Richtlinie vom Speicher zu B
e.SavePolicy()

Laden/Speichern zur Laufzeit

Sie möchten vielleicht auch das Modell neu laden, die Richtlinie neu laden oder die Richtlinie nach der Initialisierung speichern:

// 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

There is a feature called Auto-Save for adapters. When an adapter supports Auto-Save, it means it can support adding a single policy rule to the storage, or removing a single policy rule from the storage. This is unlike SavePolicy(), because the latter will delete all policy rules in the storage and save all policy rules from Casbin enforcer to the storage. So it may suffer performance issue when the number of policy rules is large.

When the adapter supports Auto-Save, you can switch this option via Enforcer.EnableAutoSave() function. The option is enabled by default (if the adapter supports it).

notiz
  1. The Auto-Save feature is optional. An adapter can choose to implement it or not.
  2. Auto-Save only works for a Casbin enforcer when the adapter the enforcer uses supports it.
  3. See the AutoSave column in the above adapter list to see if Auto-Save is supported by an adapter.

Here's an example about how to use Auto-Save:

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

// By default, the AutoSave option is enabled for an enforcer.
a := xormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")
e := casbin.NewEnforcer("examples/basic_model.conf", a)

// Disable the AutoSave option.
e.EnableAutoSave(false)

// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
// it doesn't affect the policy in the storage.
e.AddPolicy(...)
e.RemovePolicy(...)

// Enable the AutoSave option.
e.EnableAutoSave(true)

// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
// but also affects the policy in the storage.
e.AddPolicy(...)
e.RemovePolicy(...)

For more examples, please see: https://github.com/casbin/xorm-adapter/blob/master/adapter_test.go

How to write an adapter

All adapters should implement the Adapter interface by providing at least two mandatory methods:LoadPolicy(model model.Model) error and SavePolicy(model model.Model) error.

The other three functions are optional. They should be implemented if the adapter supports the Auto-Save feature.

MethodTypeDescription
LoadPolicy()mandatoryLoad all policy rules from the storage
SavePolicy()mandatorySave all policy rules to the storage
AddPolicy()optionalAdd a policy rule to the storage
RemovePolicy()optionalEntfernen Sie eine Richtlinienregel aus dem Speicher
RemoveFilteredPolicy()optionalEntfernen Sie Richtlinienregeln, die dem Filter entsprechen, aus dem Speicher
notiz

Wenn ein Adapter "Auto-Save" nicht unterstützt, sollte er eine leere Implementierung für die drei optionalen Funktionen bereitstellen. Hier ist ein Beispiel für 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 wird den Fehler "nicht implementiert" ignorieren, wenn diese drei optionalen Funktionen aufgerufen werden.

Es gibt Details darüber, wie man einen Adapter schreibt.

  • Datenstruktur. Adapter sollte das Lesen von mindestens sechs Spalten unterstützen.
  • Datenbankname. Der Standarddatenbankname sollte casbin sein.
  • Tabellenname. Der Standardtabellenname sollte casbin_rule sein.
  • Ptype-Spalte. Der Name dieser Spalte sollte ptype statt p_type oder Ptype sein.
  • Die Tabellendefinition sollte (id int primary key, ptype varchar, v0 varchar, v1 varchar, v2 varchar, v3 varchar, v4 varchar, v5 varchar) sein.
  • Der eindeutige Schlüsselindex sollte auf den Spalten ptype,v0,v1,v2,v3,v4,v5 erstellt werden.
  • LoadFilteredPolicy erfordert einen filter als Parameter. Der Filter sollte so etwas sein.
{
"p": ["", "domain1"],
"g": ["", "", "domain1"]
}

Wer ist verantwortlich für die Erstellung der DB?

Nach Konvention sollte der Adapter in der Lage sein, automatisch eine Datenbank namens casbin zu erstellen, wenn sie nicht existiert, und sie zur Richtlinienspeicherung zu verwenden. Bitte verwenden Sie den Xorm-Adapter als Referenzimplementierung: https://github.com/casbin/xorm-adapter

Update Adapter

The UpdateAdapter interface extends the basic Adapter interface to support updating policies directly in the storage. This is more efficient than removing and re-adding policies when you need to modify existing rules.

An adapter that implements the UpdateAdapter interface should provide the following methods:

MethodTypeDescription
UpdatePolicy()optionalUpdate a single policy rule in the storage
UpdatePolicies()optionalUpdate multiple policy rules in the storage
UpdateFilteredPolicies()optionalUpdate policy rules that match the filter in the storage

Beispiel

Here's an example of using the update adapter methods:

import (
"github.com/casbin/casbin/v2"
"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",
)

How to write an update adapter

To implement the UpdateAdapter interface, your adapter needs to implement the update methods in addition to the basic Adapter interface:

// 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 {
// Implementation to update the policy in storage
// For example, in SQL: 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 {
// Implementation to update multiple policies in storage
// This should be done in a transaction 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 {
// Implementation to update filtered policies in storage
// First find policies matching the filter, then update them
return nil
}
notiz

If an adapter doesn't support the UpdateAdapter interface, Casbin will automatically fall back to using the combination of RemovePolicy() and AddPolicy() operations.

Context Adapter

ContextAdapter bietet eine kontextbewusste Schnittstelle für Casbin-Adapter.

Durch den Kontext können Sie Funktionen wie die Timeout-Steuerung für die Adapter-API implementieren

Example

gormadapter unterstützt Adapter mit Kontext, das Folgende ist eine Timeout-Steuerung, die mit Kontext implementiert wird

ca, _ := NewContextAdapter("mysql", "root:@tcp(127.0.0.1:3306)/", "casbin")
// Limited time 300s
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)
}

Wie man einen Kontextadapter schreibt

ContextAdapter API hat nur eine zusätzliche Schicht der Kontextverarbeitung als gewöhnliche Adapter API, und auf der Grundlage der Implementierung gewöhnlicher Adapter API können Sie Ihre eigene Verarbeitungslogik für Kontext kapseln

A simple reference to the gormadapter: adapter.go

Transaction

Casbin now supports Transactions. Here's an example about how to use Transaction in 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.
// If the function returns an error, the transaction is rolled back.
// Otherwise, it's committed automatically.
err := e.WithTransaction(ctx, func(tx *casbin.Transaction) error {
tx.AddPolicy("alice", "data1", "read")
tx.AddPolicy("alice", "data1", "write")
return nil
})

// If you wish to manually handle the transaction
tx, _ := e.BeginTransaction(ctx)
tx.AddPolicy("alice", "data1", "write")
if err := tx.Commit(); err != nil {
// handle if transaction failed
}

To add this capability to your adapter, you need to implement TransactionalAdapter and TransactionContext in persist/transaction.go.

Code reference to the gormadapter: adapter.go