chore: remove collab ac cache (#420)

* chore: remove collab ac cache

* chore: update member write workspace role

* chore: fix test

* chore: clippy
This commit is contained in:
Nathan.fooo 2024-03-26 21:36:24 +08:00 committed by GitHub
parent 66a5033d16
commit 3e36dae50d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 57 deletions

View File

@ -23,6 +23,7 @@ pub trait CollabStorageAccessControl: Send + Sync + 'static {
async fn update_policy(&self, uid: &i64, oid: &str, level: AFAccessLevel) async fn update_policy(&self, uid: &i64, oid: &str, level: AFAccessLevel)
-> Result<(), AppError>; -> Result<(), AppError>;
/// Removes the access level of the user for given collab object.
async fn enforce_read_collab( async fn enforce_read_collab(
&self, &self,
workspace_id: &str, workspace_id: &str,
@ -30,6 +31,7 @@ pub trait CollabStorageAccessControl: Send + Sync + 'static {
oid: &str, oid: &str,
) -> Result<bool, AppError>; ) -> Result<bool, AppError>;
/// Enforce the user's permission to write to the collab object.
async fn enforce_write_collab( async fn enforce_write_collab(
&self, &self,
workspace_id: &str, workspace_id: &str,
@ -37,15 +39,16 @@ pub trait CollabStorageAccessControl: Send + Sync + 'static {
oid: &str, oid: &str,
) -> Result<bool, AppError>; ) -> Result<bool, AppError>;
/// Enforce the user's permission to write to the workspace.
async fn enforce_write_workspace(&self, uid: &i64, workspace_id: &str) -> Result<bool, AppError>;
/// Enforce the user's permission to delete the collab object.
async fn enforce_delete( async fn enforce_delete(
&self, &self,
workspace_id: &str, workspace_id: &str,
uid: &i64, uid: &i64,
oid: &str, oid: &str,
) -> Result<bool, AppError>; ) -> Result<bool, AppError>;
/// Returns the role of the user in the workspace.
async fn enforce_write_workspace(&self, uid: &i64, workspace_id: &str) -> Result<bool, AppError>;
} }
/// Represents a storage mechanism for collaborations. /// Represents a storage mechanism for collaborations.

View File

@ -1,15 +1,15 @@
use crate::biz::casbin::access_control::ObjectType; use crate::biz::casbin::access_control::ObjectType;
use crate::biz::casbin::access_control::{ use crate::biz::casbin::access_control::{
enable_access_control, AccessControl, AccessControlChange, Action, ActionVariant, enable_access_control, AccessControl, Action, ActionVariant,
}; };
use crate::biz::collab::access_control::CollabAccessControl; use crate::biz::collab::access_control::CollabAccessControl;
use app_error::AppError; use app_error::AppError;
use async_trait::async_trait; use async_trait::async_trait;
use collab_rt::RealtimeAccessControl; use collab_rt::RealtimeAccessControl;
use dashmap::DashMap;
use database_entity::dto::AFAccessLevel; use database_entity::dto::AFAccessLevel;
use std::sync::Arc;
use tracing::instrument; use tracing::instrument;
#[derive(Clone)] #[derive(Clone)]
@ -93,35 +93,25 @@ impl CollabAccessControl for CollabAccessControlImpl {
#[derive(Clone)] #[derive(Clone)]
pub struct RealtimeCollabAccessControlImpl { pub struct RealtimeCollabAccessControlImpl {
access_control: AccessControl, access_control: AccessControl,
action_by_oid: Arc<DashMap<String, Action>>,
} }
impl RealtimeCollabAccessControlImpl { impl RealtimeCollabAccessControlImpl {
pub fn new(access_control: AccessControl) -> Self { pub fn new(access_control: AccessControl) -> Self {
let action_by_oid = Arc::new(DashMap::new()); // let action_by_oid = Arc::new(DashMap::new());
let mut sub = access_control.subscribe_change(); // let mut sub = access_control.subscribe_change();
let weak_action_by_oid = Arc::downgrade(&action_by_oid); // let weak_action_by_oid = Arc::downgrade(&action_by_oid);
// tokio::spawn(async move {
tokio::spawn(async move { // while let Ok(change) = sub.recv().await {
while let Ok(change) = sub.recv().await { // match weak_action_by_oid.upgrade() {
match weak_action_by_oid.upgrade() { // None => break,
None => break, // Some(action_by_oid) => match change {
Some(action_by_oid) => match change { // AccessControlChange::UpdatePolicy { uid, oid } => {},
AccessControlChange::UpdatePolicy { uid, oid } => { // AccessControlChange::RemovePolicy { uid, oid } => {},
action_by_oid.remove(&cache_key(uid, &oid)); // },
}, // }
AccessControlChange::RemovePolicy { uid, oid } => { // }
action_by_oid.remove(&cache_key(uid, &oid)); // });
}, Self { access_control }
},
}
}
});
Self {
access_control,
action_by_oid,
}
} }
async fn can_perform_action( async fn can_perform_action(
@ -132,13 +122,6 @@ impl RealtimeCollabAccessControlImpl {
required_action: Action, required_action: Action,
) -> Result<bool, AppError> { ) -> Result<bool, AppError> {
if enable_access_control() { if enable_access_control() {
let key = cache_key(*uid, oid);
// Check if the action is already cached
if let Some(action) = self.action_by_oid.get(&key) {
return Ok(*action >= required_action);
}
// Not in cache, enforce access control
let is_permitted = self let is_permitted = self
.access_control .access_control
.enforce( .enforce(
@ -149,11 +132,6 @@ impl RealtimeCollabAccessControlImpl {
) )
.await?; .await?;
if is_permitted {
// Permission granted, cache the action
self.action_by_oid.insert(key, required_action);
}
Ok(is_permitted) Ok(is_permitted)
} else { } else {
Ok(true) Ok(true)
@ -161,11 +139,6 @@ impl RealtimeCollabAccessControlImpl {
} }
} }
#[inline]
fn cache_key(uid: i64, oid: &str) -> String {
format!("{}:{}", uid, oid)
}
#[async_trait] #[async_trait]
impl RealtimeAccessControl for RealtimeCollabAccessControlImpl { impl RealtimeAccessControl for RealtimeCollabAccessControlImpl {
async fn can_write_collab( async fn can_write_collab(

View File

@ -7,7 +7,7 @@ use actix_web::http::Method;
use app_error::AppError; use app_error::AppError;
use async_trait::async_trait; use async_trait::async_trait;
use database::collab::CollabStorageAccessControl; use database::collab::CollabStorageAccessControl;
use database_entity::dto::{AFAccessLevel, AFRole}; use database_entity::dto::AFAccessLevel;
use crate::biz::collab::cache::CollabCache; use crate::biz::collab::cache::CollabCache;
@ -218,6 +218,13 @@ where
.await .await
} }
async fn enforce_write_workspace(&self, uid: &i64, workspace_id: &str) -> Result<bool, AppError> {
self
.workspace_access_control
.enforce_action(uid, workspace_id, Action::Write)
.await
}
async fn enforce_delete( async fn enforce_delete(
&self, &self,
workspace_id: &str, workspace_id: &str,
@ -229,11 +236,4 @@ where
.enforce_access_level(workspace_id, uid, oid, AFAccessLevel::FullAccess) .enforce_access_level(workspace_id, uid, oid, AFAccessLevel::FullAccess)
.await .await
} }
async fn enforce_write_workspace(&self, uid: &i64, workspace_id: &str) -> Result<bool, AppError> {
self
.workspace_access_control
.enforce_role(uid, workspace_id, AFRole::Owner)
.await
}
} }

View File

@ -172,7 +172,6 @@ where
} }
#[instrument(level = "trace", skip(self, params), oid = %params.oid, err)] #[instrument(level = "trace", skip(self, params), oid = %params.oid, err)]
#[allow(clippy::blocks_in_if_conditions)]
async fn insert_or_update_collab_with_transaction( async fn insert_or_update_collab_with_transaction(
&self, &self,
workspace_id: &str, workspace_id: &str,
@ -188,6 +187,11 @@ where
// When the collab is not exist in the database, and the user passes the permission check, // When the collab is not exist in the database, and the user passes the permission check,
// which means the user has the permission to create the collab, we should update the policy // which means the user has the permission to create the collab, we should update the policy
if !is_collab_exist_in_db { if !is_collab_exist_in_db {
trace!(
"Update policy for user:{} to create collab:{}",
uid,
params.object_id
);
self self
.access_control .access_control
.update_policy(uid, &params.object_id, AFAccessLevel::FullAccess) .update_policy(uid, &params.object_id, AFAccessLevel::FullAccess)