mod logger;
use std::{
ops::{Deref, DerefMut},
sync::Arc,
};
pub use casbin::{self, EnforceArgs, function_map::OperatorFunction, prelude::*};
pub use logger::TraceLogger;
use salvo::prelude::*;
pub use salvo_casbin::{CasbinHoop, CasbinVals};
use sea_orm::DatabaseConnection;
use sea_orm_adapter::SeaOrmAdapter;
use tokio::sync::RwLock;
pub struct Authz<F>(CasbinHoop<CachedEnforcer, F>);
#[handler]
impl<F> Authz<F>
where
F: Fn(&mut Request, &mut Depot) -> std::result::Result<Option<CasbinVals>, StatusError> + Send + Sync + 'static,
{
pub async fn new(db_conn: DatabaseConnection, model_str: &str, get_casbin_vals: F) -> anyhow::Result<Self> {
let m = DefaultModel::from_str(model_str).await?;
let a = SeaOrmAdapter::new(db_conn).await?;
let mut e = CachedEnforcer::new(m, a).await?;
e.set_logger(Box::new(logger::TraceLogger::default()));
e.enable_log(true);
Ok(Self(CasbinHoop::new(e, false, get_casbin_vals)))
}
pub fn get_enforcer(&self) -> Arc<RwLock<CachedEnforcer>> {
self.0.get_enforcer()
}
#[inline(always)]
pub async fn handle(&self, req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
self.0.handle(req, depot, res, ctrl).await
}
}
impl<F> Deref for Authz<F> {
type Target = Arc<RwLock<CachedEnforcer>>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl<F> DerefMut for Authz<F> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.deref_mut()
}
}
#[cfg(test)]
mod test {
use super::*;
#[tokio::test]
#[should_panic]
async fn test_optimal_enforcer() {
let e = Authz::new(Default::default(), Default::default(), |_req, _depot| {
Ok(Some(CasbinVals {
subject: String::from("alice"),
domain: None,
}))
})
.await
.unwrap();
let _ = salvo::Router::with_hoop(e);
}
}