casbin / casbin-rs

An authorization library that supports access control models like ACL, RBAC, ABAC in Rust.
https://casbin.org
Apache License 2.0
828 stars 67 forks source link

How to dynamically add a policy to a lazy static environment #288

Closed jiashiwen closed 2 years ago

jiashiwen commented 2 years ago

hi: I need a static singleton to manage permissions, so I use lazy Static and AsyncOnce to build static variables. I can call enfore for authentication, but dynamic add policy fails my code

use async_once::AsyncOnce;
use casbin::prelude::*;
use casbin::MemoryAdapter;
use casbin::Result;

lazy_static::lazy_static! {
    static ref GLOBALE_CASBIN_ENFORCER: AsyncOnce<CasbinEnforcer> = AsyncOnce::new(async {
        CasbinEnforcer::default().await
    });
}
pub struct CasbinEnforcer {
    enforcer: Enforcer,
}

impl CasbinEnforcer {
    pub async fn default() -> Self {
        let m = DefaultModel::from_file("./rbac_with_domains_model.conf")
            .await
            .unwrap()

        let a = MemoryAdapter::default();

        let mut enforcer = Enforcer::new(m, a).await.unwrap();
        let p = vec![
            "jsw".to_string(),
            "domain1".to_string(),
            "data2".to_string(),
            "read".to_string(),
        ];

        enforcer.add_policy(p).await.unwrap();

        Self {
            enforcer,
        }
    }

    pub async fn addpolice(&mut self, p: Vec<String>) -> Result<bool> {
        self.enforcer.add_policy(p).await
    }
}

pub async fn enfoce(args: Vec<String>) -> Result<bool> {
    GLOBALE_CASBIN_ENFORCER.get().await.enforcer.enforce(args)
}

pub async fn add_policy(p: Vec<String>) -> Result<bool> {
    GLOBALE_CASBIN_ENFORCER.get().await.addpolice(p).await
}

#[tokio::main]
async fn main() -> Result<()> {

    let args = vec![
        "jsw".to_string(),
        "domain".to_string(),
        "data2".to_string(),
        "read".to_string(),
    ];

    add_policy(args.clone()).await;

    let r = enfoce(args).await;
    println!("{:?}", r);
    Ok(())
}

error

error[E0596]: cannot borrow data in a `&` reference as mutable
  --> examples/casbin_test.rs:73:5
   |
73 |     GLOBALE_CASBIN_ENFORCER.get().await.addpolice(p).await
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

For more information about this error, try `rustc --explain E0596`.
error: could not compile `serverframe-rs` due to previous error

how to resole this

casbin-bot commented 2 years ago

@smrpn @hackerchai @PsiACE @GopherJ

jiashiwen commented 2 years ago

this is a question

jiashiwen commented 2 years ago

use futures_locks::RwLock can resolve this

use async_once::AsyncOnce;
use casbin::prelude::*;
use casbin::MemoryAdapter;
use casbin::Result;
use futures_locks::RwLock;

lazy_static::lazy_static! {
    static ref GLOBALE_CASBIN_ENFORCER: AsyncOnce<RwLock<CasbinEnforcer>> = AsyncOnce::new(async {
        let ce=CasbinEnforcer::default().await;
        RwLock::new(ce)
    });
}
pub struct CasbinEnforcer {
    enforcer: Enforcer,
}

impl CasbinEnforcer {
    pub async fn default() -> Self {
        let m = DefaultModel::from_file("./rbac_with_domains_model.conf")
            .await
            .unwrap();

        let a = MemoryAdapter::default();
        let mut enforcer = Enforcer::new(m, a).await.unwrap();
        let p = vec![
            "jsw".to_string(),
            "domain1".to_string(),
            "data2".to_string(),
            "read".to_string(),
        ];

        enforcer.add_policy(p).await.unwrap();
        Self { enforcer }
    }

    pub async fn addpolice(&mut self, p: Vec<String>) -> Result<bool> {
        self.enforcer.add_policy(p).await
    }
}

pub async fn casbin_enforce(args: Vec<String>) -> Result<bool> {
    GLOBALE_CASBIN_ENFORCER
        .get()
        .await
        .read()
        .await
        .enforcer
        .enforce(args)
}

pub async fn add_policy(p: Vec<String>) -> Result<bool> {
    GLOBALE_CASBIN_ENFORCER
        .get()
        .await
        .write()
        .await
        .addpolice(p)
        .await
}