Ent Adapter is the Ent adapter for Casbin. With this library, Casbin can load policy from Ent-supported databases or save policy to them.
Based on Ent Supported Drivers, the current supported databases are:
go get github.com/apache/casbin-ent-adapter
package main import ( "github.com/casbin/casbin/v3" entadapter "github.com/apache/casbin-ent-adapter" _ "github.com/go-sql-driver/mysql" ) func main() { // Initialize an Ent adapter and use it in a Casbin enforcer: // The adapter will use the MySQL database named "casbin". // The database should be created manually before using the adapter. a, _ := entadapter.NewAdapter("mysql", "root:@tcp(127.0.0.1:3306)/casbin") // Your driver and data source. e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a) // Load the policy from DB. e.LoadPolicy() // Check the permission. e.Enforce("alice", "data1", "read") // Modify the policy. // e.AddPolicy(...) // e.RemovePolicy(...) // Save the policy back to DB. e.SavePolicy() }
package main import ( "github.com/casbin/casbin/v3" entadapter "github.com/apache/casbin-ent-adapter" _ "github.com/lib/pq" ) func main() { // Initialize an Ent adapter and use it in a Casbin enforcer: // The adapter will use the PostgreSQL database named "casbin". // The database should be created manually before using the adapter. a, _ := entadapter.NewAdapter("postgres", "user=postgres password=postgres host=127.0.0.1 port=5432 sslmode=disable dbname=casbin") // Your driver and data source. e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a) // Load the policy from DB. e.LoadPolicy() // Check the permission. e.Enforce("alice", "data1", "read") // Modify the policy. // e.AddPolicy(...) // e.RemovePolicy(...) // Save the policy back to DB. e.SavePolicy() }
You can also create an adapter with an existing Ent client instance:
package main import ( "github.com/casbin/casbin/v3" entadapter "github.com/apache/casbin-ent-adapter" "github.com/apache/casbin-ent-adapter/ent" ) func main() { // Create an Ent client client, _ := ent.Open("mysql", "root:@tcp(127.0.0.1:3306)/casbin") // Initialize an Ent adapter with the client a, _ := entadapter.NewAdapterWithClient(client) e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a) // Load the policy from DB. e.LoadPolicy() // Check the permission. e.Enforce("alice", "data1", "read") // Save the policy back to DB. e.SavePolicy() }
The database used in the adapter should be created manually before calling NewAdapter. The adapter will automatically create the casbin_rule table if it doesn't exist.
A policy rule is now unique on (ptype, v0, v1, v2, v3, v4, v5), and the seven columns are varchar(100) so that the index fits within the 3072-byte key limit InnoDB enforces. Both are enforced by the automatic migration that runs inside NewAdapter and NewAdapterWithClient, so a database written by an earlier version needs a look before the first start on this version. A fresh database needs nothing.
Check for rules that no longer fit. The adapter runs this check itself and refuses to migrate while it returns anything, because a MySQL server running without strict mode would truncate the values rather than reject them:
SELECT * FROM casbin_rules WHERE CHAR_LENGTH(ptype) > 100 OR CHAR_LENGTH(v0) > 100 OR CHAR_LENGTH(v1) > 100 OR CHAR_LENGTH(v2) > 100 OR CHAR_LENGTH(v3) > 100 OR CHAR_LENGTH(v4) > 100 OR CHAR_LENGTH(v5) > 100;
Check for rules stored more than once. Nothing enforced uniqueness before, so duplicates may have accumulated, and the index cannot be built while they exist:
SELECT ptype, v0, v1, v2, v3, v4, v5, COUNT(*) AS copies FROM casbin_rules GROUP BY ptype, v0, v1, v2, v3, v4, v5 HAVING COUNT(*) > 1;
Duplicates are redundant by definition — casbin evaluates a rule the same way whether it is stored once or ten times — so keeping the lowest id of each group is safe:
DELETE c FROM casbin_rules c JOIN ( SELECT MIN(id) AS keep_id, ptype, v0, v1, v2, v3, v4, v5 FROM casbin_rules GROUP BY ptype, v0, v1, v2, v3, v4, v5 HAVING COUNT(*) > 1 ) d ON c.ptype = d.ptype AND c.v0 = d.v0 AND c.v1 = d.v1 AND c.v2 = d.v2 AND c.v3 = d.v3 AND c.v4 = d.v4 AND c.v5 = d.v5 WHERE c.id > d.keep_id;
On PostgreSQL, use DELETE FROM casbin_rules WHERE id NOT IN (SELECT MIN(id) FROM casbin_rules GROUP BY ptype, v0, v1, v2, v3, v4, v5); instead.
Adding a rule that is already stored stays a successful no-op rather than becoming an error, so replicas whose in-memory model has fallen behind another writer keep working.
This project is under Apache 2.0 License. See the LICENSE file for the full license text.