Giter Site home page Giter Site logo

casbin-rs / sqlx-adapter Goto Github PK

View Code? Open in Web Editor NEW
45.0 4.0 21.0 204 KB

Asynchronous casbin adapter for mysql, postgres, sqlite based on sqlx-rs

Home Page: https://github.com/casbin/casbin-rs

License: Apache License 2.0

Shell 2.74% Rust 97.26%
sqlx-adapter postgres mysql casbin casbin-rs rust rbac abac acl permission

sqlx-adapter's Introduction

sqlx-adapter

Crates.io Docs CI codecov

sqlx-adapter is the Sqlx adapter for casbin-rs. With this library, Casbin can load policy from Sqlx supported database or save policy to it with fully asynchronous support.

Based on Sqlx, The current supported databases are:

Notice

In order to unify the database table name in Casbin ecosystem, we decide to use casbin_rule instead of casbin_rules from version 0.4.0. If you are using old version sqlx-adapter in your production environment, please use following command and update sqlx-adapter version:

# MySQL & PostgreSQL & SQLite
ALTER TABLE casbin_rules RENAME TO casbin_rule;

Install

Add the following to Cargo.toml:

For MySQL:

sqlx-adapter = { version = "1.2.0", default-features = false, features = ["mysql", "runtime-tokio-native-tls"]}
tokio = { version = "1.1.1", features = ["macros"] }

For PostgreSQL:

sqlx-adapter = { version = "1.2.0", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]}
tokio = { version = "1.1.1", features = ["macros"] }

For SQLite:

sqlx-adapter = { version = "1.2.0", default-features = false, features = ["sqlite", "runtime-tokio-native-tls"]}
tokio = { version = "1.1.1", features = ["macros"] }

Warning: tokio v1.0 or later is supported from sqlx-adapter v0.4.0, we recommend that you upgrade the relevant components to ensure that they work properly. The last version that supports tokio v0.2 is sqlx-adapter v0.3.0 , you can choose according to your needs.

Configure

  1. Set up database environment

    You must prepare the database environment so that Sqlx can do static check with queries during compile time. One convenient option is using docker to get your database environment ready:

    #!/bin/bash
    
    DIS=$(lsb_release -is)
    
    command -v docker > /dev/null 2>&1 || {
        echo "Please install docker before running this script." && exit 1;
    }
    
    if [ $DIS == "Ubuntu" ] || [ $DIS == "LinuxMint" ]; then
        sudo apt install -y \
            libpq-dev \
            libmysqlclient-dev \
            postgresql-client \
            mysql-client-core;
    
    elif [ $DIS == "Deepin" ]; then
        sudo apt install -y \
            libpq-dev \
            libmysql++-dev \
            mysql-client \
            postgresql-client;
    elif [ $DIS == "ArchLinux" ] || [ $DIS == "ManjaroLinux" ]; then
        sudo pacman -S libmysqlclient \
            postgresql-libs \
            mysql-clients \;
    else
        echo "Unsupported system: $DIS" && exit 1;
    fi
    
    docker run -itd \
        --restart always \
        -e POSTGRES_USER=casbin_rs \
        -e POSTGRES_PASSWORD=casbin_rs \
        -e POSTGRES_DB=casbin \
        -p 5432:5432 \
        -v /srv/docker/postgresql:/var/lib/postgresql \
        postgres:11;
    
    docker run -itd \
        --restart always \
        -e MYSQL_ALLOW_EMPTY_PASSWORD=yes \
        -e MYSQL_USER=casbin_rs \
        -e MYSQL_PASSWORD=casbin_rs \
        -e MYSQL_DATABASE=casbin \
        -p 3306:3306 \
        -v /srv/docker/mysql:/var/lib/mysql \
        mysql:8 \
        --default-authentication-plugin=mysql_native_password;
    
  2. Create table casbin_rule

    # PostgreSQL
    psql postgres://casbin_rs:[email protected]:5432/casbin -c "CREATE TABLE IF NOT EXISTS casbin_rule (
        id SERIAL PRIMARY KEY,
        ptype VARCHAR NOT NULL,
        v0 VARCHAR NOT NULL,
        v1 VARCHAR NOT NULL,
        v2 VARCHAR NOT NULL,
        v3 VARCHAR NOT NULL,
        v4 VARCHAR NOT NULL,
        v5 VARCHAR NOT NULL,
        CONSTRAINT unique_key_sqlx_adapter UNIQUE(ptype, v0, v1, v2, v3, v4, v5)
        );"
    
    # MySQL
    mysql -h 127.0.0.1 -u casbin_rs -pcasbin_rs casbin 
    
    CREATE TABLE IF NOT EXISTS casbin_rule (
        id INT NOT NULL AUTO_INCREMENT,
        ptype VARCHAR(12) NOT NULL,
        v0 VARCHAR(128) NOT NULL,
        v1 VARCHAR(128) NOT NULL,
        v2 VARCHAR(128) NOT NULL,
        v3 VARCHAR(128) NOT NULL,
        v4 VARCHAR(128) NOT NULL,
        v5 VARCHAR(128) NOT NULL,
        PRIMARY KEY(id),
        CONSTRAINT unique_key_sqlx_adapter UNIQUE(ptype, v0, v1, v2, v3, v4, v5)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    # SQLite
    touch casbin.db
    
    sqlite3 casbin.db -cmd "CREATE TABLE IF NOT EXISTS casbin_rule (
       id INTEGER PRIMARY KEY,
       ptype VARCHAR(12) NOT NULL,
       v0 VARCHAR(128) NOT NULL,
       v1 VARCHAR(128) NOT NULL,
       v2 VARCHAR(128) NOT NULL,
       v3 VARCHAR(128) NOT NULL,
       v4 VARCHAR(128) NOT NULL,
       v5 VARCHAR(128) NOT NULL,
       CONSTRAINT unique_key_diesel_adapter UNIQUE(ptype, v0, v1, v2, v3, v4, v5)
       );"
  3. Configure env

    Rename sample.env to .env and put DATABASE_URL, POOL_SIZE inside

    DATABASE_URL=postgres://casbin_rs:casbin_rs@localhost:5432/casbin
    # DATABASE_URL=mysql://casbin_rs:casbin_rs@localhost:3306/casbin
    # DATABASE_URL=sqlite:casbin.db
    POOL_SIZE=8

    Or you can export DATABASE_URL, POOL_SIZE

    export DATABASE_URL=postgres://casbin_rs:casbin_rs@localhost:5432/casbin
    export POOL_SIZE=8

Example

use sqlx_adapter::casbin::prelude::*;
use sqlx_adapter::casbin::Result;
use sqlx_adapter::SqlxAdapter;

#[tokio::main]
async fn main() -> Result<()> {
    let m = DefaultModel::from_file("examples/rbac_model.conf").await?;
    
    let a = SqlxAdapter::new("postgres://casbin_rs:[email protected]:5432/casbin", 8).await?;
    let mut e = Enforcer::new(m, a).await?;
    
    Ok(())
}

Features

  • postgres
  • mysql
  • sqlite

Attention: postgres, mysql, sqlite are mutual exclusive which means that you can only activate one of them.

sqlx-adapter's People

Contributors

andoriyu avatar dependabot-preview[bot] avatar gopherj avatar greenhandatsjtu avatar hackerchai avatar hgz-20 avatar hsluoyz avatar jgrund avatar muzhou233 avatar psiace avatar siddheshkanawade avatar uran0sh avatar zbrox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

sqlx-adapter's Issues

Dynamic sqlx compile support

When we use CI/CD, we have to set up database and create tables in order to build the adapter. Also when developers use sqlx-adapter, they don't need to verify the SQL syntax. I think we should add dynamic compile feature to avoid compile-time SQL verify.

More efficient `load_filtered_policy`

When working with a large policy it makes sense only to load a subset of policies to make the enforcement decision.

This adapter unfortunately loads all the rules and filters them in memory.

Would you accept a PR that moves the filter / selection logic into an SQL query for performance / efficiency?

Adding sqlx-adapter to the project breaks compilation

I have a workspace project. In one of the sub-projects, I'm already using sqlx and tokio:

casbin = "2.0.2"
sqlx = {version = "0.5", features = ["json", "offline", "postgres", "runtime-tokio-rustls", "chrono"]}
tokio = {version = "1", features = ["macros", "rt-multi-thread"]}
...

I then add sqlx-adapter to Cargo.toml:

casbin = "2.0.2"
sqlx = {version = "0.5", features = ["json", "offline", "postgres", "runtime-tokio-rustls", "chrono"]}
tokio = {version = "1", features = ["macros", "rt-multi-thread"]}
sqlx-adapter = { version = "0.4.1", features = ["postgres"] }

And try to compile:

➜  git:(master) ✗ cargo check
   Compiling sqlx-rt v0.5.5
    Checking casbin v2.0.7
error: only one of ['runtime-actix-native-tls', 'runtime-async-std-native-tls', 'runtime-tokio-native-tls', 'runtime-actix-rustls', 'runtime-async-std-rustls', 'runtime-tokio-rustls'] can be enabled
  --> /home/mkpankov/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-rt-0.5.5/src/lib.rs:21:1
   |
21 | / compile_error!(
22 | |     "only one of ['runtime-actix-native-tls', 'runtime-async-std-native-tls', \
23 | |      'runtime-tokio-native-tls', 'runtime-actix-rustls', 'runtime-async-std-rustls', \
24 | |      'runtime-tokio-rustls'] can be enabled"
25 | | );
   | |__^

error: aborting due to previous error

error: could not compile `sqlx-rt`

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...

There's following diff in the Cargo.lock:

diff --git a/Cargo.lock b/Cargo.lock
index 9e1602cd6..c7ec331f4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -495,6 +495,7 @@ dependencies = [
  "rhai",
  "serde 1.0.126",
  "thiserror",
+ "tokio",
 ]

 [[package]]
@@ -1153,6 +1154,7 @@ dependencies = [
  "serde_json",
  "serde_yaml",
  "sqlx",
+ "sqlx-adapter",
  "thiserror",
  "tokio",
  "tokio-runtime-panic-fix",
@@ -4228,6 +4230,18 @@ dependencies = [
  "sqlx-macros",
 ]

+[[package]]
+name = "sqlx-adapter"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32bd18442e437cf667268f0b3f0b73519342d25a5a87c0d6e518ba0541f26528"
+dependencies = [
+ "async-trait",
+ "casbin",
+ "dotenv",
+ "sqlx",
+]
+
 [[package]]
 name = "sqlx-core"
 version = "0.5.5"
@@ -4309,8 +4323,10 @@ version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8199b421ecf3493ee9ef3e7bc90c904844cfb2ea7ea2f57347a93f52bfd3e057"
 dependencies = [
+ "native-tls",
  "once_cell",
  "tokio",
+ "tokio-native-tls",
  "tokio-rustls",
 ]

It looks like there are hardcoded sqlx features in the sqlx-adapter that collide with features I'm using.

Improve introduction in README

Use the template of this: https://github.com/casbin/xorm-adapter#xorm-adapter---

This part:

Xorm Adapter is the [Xorm](https://gitea.com/xorm/xorm) adapter for [Casbin](https://github.com/casbin/casbin). With this library, Casbin can load policy from Xorm supported database or save policy to it.

Based on [Xorm Drivers Support](https://gitea.com/xorm/xorm#drivers-support), The current supported databases are:

- Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
- MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
- Postgres: [github.com/lib/pq](https://github.com/lib/pq)
- Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
- SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
- MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
- Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)

MySQL & PostgreSQL compatible query macro

Currently I have to write code like this to support MySQL and PostgreSQL query.

#[cfg(feature = "postgres")]
    sqlx::query!(
        "DELETE FROM tables WHERE
                    ptype = $1 AND
                    v0 = $2 AND
                    v1 = $3 AND
                    v2 = $4 AND
                    v3 = $5 AND
                    v4 = $6 AND
                    v5 = $7",
        pt.to_string(),
        rule[0],
        rule[1],
        rule[2],
        rule[3],
        rule[4],
        rule[5]
    )
    .execute(&mut conn)
#[cfg(feature = "mysql")]
sqlx::query!(
        "DELETE FROM tables WHERE
                    ptype = ? AND
                    v0 = ? AND
                    v1 = ? AND
                    v2 = ? AND
                    v3 = ? AND
                    v4 = ? AND
                    v5 = ?",
        pt.to_string(),
        rule[0],
        rule[1],
        rule[2],
        rule[3],
        rule[4],
        rule[5]
    )
    .execute(&mut conn)

I think a custom macro will help to avoid duplicated codes like this.

rename unique constraint name

It seems sometimes diesel-adapter and sqlx-adapter can have problem of duplicated constraint name,

CONSTRAINT unique_key UNIQUE(ptype, v0, v1, v2, v3, v4, v5)

I'll rename unique_key to unique_key_diesel_adapter, could you rename unique_key to unique_key_sqlx_adapter?

sqlite feature request

Hi, it would be very nice to have an SQLite feature for new bees. In addition, with this feature, those who need to do a proof of concept become more simple and agile.

sqlx changed features names

Hello, sqlx just changed the feature names from runtime-tokio and runtime-async-std to runtime-{rt}-{tls} where rt is tokio, actix or async-std and tls is native-tls or rustls.

This is currently breaking the compilation on some of my projects, should I open a PR?

features = ["mysql"] can't run

tokio = { "version" = "1.32.0", features = ["full"] }
sqlx-adapter = {version = "0.4.2",features = ["mysql"]}

   Compiling sqlx-adapter v0.4.2
error[E0428]: the name `ConnectionPool` is defined multiple times
  --> /Users/vincent/.cargo/registry/src/rsproxy.cn-8f6827c7555bfaf8/sqlx-adapter-0.4.2/src/actions.rs:22:1
   |
19 | pub type ConnectionPool = sqlx::PgPool;
   | --------------------------------------- previous definition of the type `ConnectionPool` here
...
22 | pub type ConnectionPool = sqlx::MySqlPool;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ConnectionPool` redefined here
   |
   = note: `ConnectionPool` must be defined only once in the type namespace of this module

error[E0428]: the name `new` is defined multiple times
  --> /Users/vincent/.cargo/registry/src/rsproxy.cn-8f6827c7555bfaf8/sqlx-adapter-0.4.2/src/actions.rs:70:1
   |
28 | pub async fn new(conn: &ConnectionPool) -> Result<PgQueryResult> {
   | ---------------------------------------------------------------- previous definition of the value `new` here
...
70 | pub async fn new(conn: &ConnectionPool) -> Result<MySqlQueryResult> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `new` redefined here
   |
   = note: `new` must be defined only once in the value namespace of this module

RbacApi::delete_user() does not remove grouping policy

While adding a role to a user and then deleting the user works when using FileAdapter, it fails when using sqlx-adapter. I've prepared a minimal sample project here that shows the issue.

Steps to repro

  • Assign a role to a user via add_role_for_user()
  • Call delete_user()

Expected outcome

Actual outcome

  • 'g' policy is deleted when using FileAdapter, but not when using sqlx-adapter

Related

There was a similar issue for node-casbin: casbin/node-casbin#118

Need changelog for every release

@GopherJ @hackerchai @PsiACE , currently, for several repos, it's very hard to know what features and bugs have been added/resolved in each release:

https://github.com/casbin-rs/sqlx-adapter/releases
https://github.com/casbin-rs/actix-casbin/releases
https://github.com/casbin-rs/diesel-adapter/releases
https://github.com/casbin-rs/actix-casbin-auth/releases

The Releases page all contain useless information like Release x.y.z, bump to x.y.z, merge PR, etc. This is not friendly for our users as they can gain nothing from the changelog. I hope we can have some sort of changelog that shows what have been done in each release.

image

When using mysql database: the trait `From<Option<String>>` is not implemented for `String`

rustc 1.75.0 (82e1608df 2023-12-21) (built from a source tarball)
tokio = { version = "1.36.0", features = ["full"] }
sqlx-adapter = { version = "1.2.0", default-features = false, features = ["mysql", "runtime-tokio-native-tls"]}

Following error happens when I'm trying to use mysql database.
In the case I use postgres database the code compiles without any issues.

error[E0277]: the trait bound `String: From<Option<String>>` is not satisfied
   --> sqlx-adapter-1.2.0/src/actions.rs:616:40
    |
616 |     let casbin_rule: Vec<CasbinRule> = sqlx::query_as!(CasbinRule, "SELECT * FROM casbin_rule")
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Option<String>>` is not implemented for `String`
    |
    = help: the following other types implement trait `From<T>`:
              <String as From<char>>
              <String as From<smartstring::boxed::BoxedString>>
              <String as From<Box<str>>>
              <String as From<smartstring::SmartString<Mode>>>
              <String as From<Cow<'a, str>>>
              <String as From<url::Url>>
              <String as From<der::asn1::utf8_string::Utf8StringRef<'a>>>
              <String as From<rhai::tokenizer::Token>>
            and 5 others
    = note: required for `Option<String>` to implement `Into<String>`
    = note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `String: From<Option<String>>` is not satisfied
   --> sqlx-adapter-1.2.0/src/actions.rs:677:40
    |
677 |       let casbin_rule: Vec<CasbinRule> = sqlx::query_as!(
    |  ________________________________________^
678 | |         CasbinRule,
679 | |         "SELECT * from  casbin_rule WHERE (
680 | |             ptype LIKE 'g%' AND v0 LIKE ? AND v1 LIKE ? AND v2 LIKE ? AND v3 LIKE ? AND v4 LIKE ? AND v5 LIKE ? )
...   |
685 | |             p_filter[0], p_filter[1], p_filter[2], p_filter[3], p_filter[4], p_filter[5],
686 | |     )
    | |_____^ the trait `From<Option<String>>` is not implemented for `String`
    |
    = help: the following other types implement trait `From<T>`:
              <String as From<char>>
              <String as From<smartstring::boxed::BoxedString>>
              <String as From<Box<str>>>
              <String as From<smartstring::SmartString<Mode>>>
              <String as From<Cow<'a, str>>>
              <String as From<url::Url>>
              <String as From<der::asn1::utf8_string::Utf8StringRef<'a>>>
              <String as From<rhai::tokenizer::Token>>
            and 5 others
    = note: required for `Option<String>` to implement `Into<String>`
    = note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query_as` (in Nightly builds, run with -Z macro-backtrace for more info)

After looking the error again, I guess it origins from sqlx::query_as and it's not related to sqlx-adapter after all

add support for AnyPool

Add support for AnyPool such that database can be chosen at runtime. match can then be used to run specific queries.

match pool.any_kind() {
    AnyKind::Postgres => {...},
    AnyKind::Sqlite => {...},
    AnyKind::MySql => {...},
}

update dependencies

  1. the casbin 2.1.0 is not supported by the adapter of version=0.4.2
  2. the sqlx is outdated. the supported version is 0.6. the actual version is 0.7.3

Use with existing connection pool

We're using sqlx with Postgres using PgPool.

It would be good if we could pass the pool to the SqlxAdapter instead of it initiating a new connection by itself.

RbacApi::delete_permissions_for_user seems to be no-op

Always returns false and sqlx shows zero queries made in database. Permissions don't get deleted.

RbacApi::delete_permission_for_user does work as expected.

Crate versions:

casbin = "2.0.9"
sqlx-adapter = { version = "0.4.2", default-features = false, features = ["runtime-tokio-native-tls", "sqlite"] }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.