feat: add transformer and refactor graphql guards
This commit is contained in:
parent
2a5c2b18e7
commit
68aa13e216
@ -4,11 +4,8 @@ use async_graphql::dynamic::{ResolverContext, ValueAccessor};
|
|||||||
use sea_orm::EntityTrait;
|
use sea_orm::EntityTrait;
|
||||||
use seaography::{BuilderContext, FnGuard, GuardAction};
|
use seaography::{BuilderContext, FnGuard, GuardAction};
|
||||||
|
|
||||||
use super::util::get_entity_key;
|
use super::util::{get_column_key, get_entity_key};
|
||||||
use crate::{
|
use crate::auth::{AuthError, AuthUserInfo};
|
||||||
auth::{AuthError, AuthUserInfo},
|
|
||||||
graphql::util::get_column_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn guard_data_object_accessor_with_subscriber_id(
|
fn guard_data_object_accessor_with_subscriber_id(
|
||||||
value: ValueAccessor<'_>,
|
value: ValueAccessor<'_>,
|
||||||
@ -50,27 +47,20 @@ fn guard_data_object_accessor_with_optional_subscriber_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guard_filter_object_accessor_with_subscriber_id(
|
pub fn guard_entity_with_subscriber_id<T>(_context: &BuilderContext, _column: &T::Column) -> FnGuard
|
||||||
value: ValueAccessor<'_>,
|
where
|
||||||
column_name: &str,
|
T: EntityTrait,
|
||||||
subscriber_id: i32,
|
<T as EntityTrait>::Model: Sync,
|
||||||
) -> async_graphql::Result<()> {
|
{
|
||||||
let obj = value.object()?;
|
Box::new(move |context: &ResolverContext| -> GuardAction {
|
||||||
let subscriber_id_filter_input_value = obj.try_get(column_name)?;
|
match context.ctx.data::<AuthUserInfo>() {
|
||||||
|
Ok(_) => GuardAction::Allow,
|
||||||
let subscriber_id_filter_input_obj = subscriber_id_filter_input_value.object()?;
|
Err(err) => GuardAction::Block(Some(err.message)),
|
||||||
|
|
||||||
let subscriber_id_value = subscriber_id_filter_input_obj.try_get("eq")?;
|
|
||||||
|
|
||||||
let id = subscriber_id_value.i64()?;
|
|
||||||
if id == subscriber_id as i64 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(async_graphql::Error::new("subscriber not match"))
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn guard_entity_with_subscriber_id<T>(context: &BuilderContext, column: &T::Column) -> FnGuard
|
pub fn guard_field_with_subscriber_id<T>(context: &BuilderContext, column: &T::Column) -> FnGuard
|
||||||
where
|
where
|
||||||
T: EntityTrait,
|
T: EntityTrait,
|
||||||
<T as EntityTrait>::Model: Sync,
|
<T as EntityTrait>::Model: Sync,
|
||||||
@ -95,23 +85,13 @@ where
|
|||||||
));
|
));
|
||||||
let entity_create_batch_mutation_data_field_name =
|
let entity_create_batch_mutation_data_field_name =
|
||||||
Arc::new(context.entity_create_batch_mutation.data_field.clone());
|
Arc::new(context.entity_create_batch_mutation.data_field.clone());
|
||||||
let entity_delete_mutation_field_name = Arc::new(format!(
|
|
||||||
"{}{}",
|
|
||||||
entity_name,
|
|
||||||
context.entity_delete_mutation.mutation_suffix.clone()
|
|
||||||
));
|
|
||||||
let entity_delete_mutation_filter_field_name =
|
|
||||||
Arc::new(context.entity_delete_mutation.filter_field.clone());
|
|
||||||
let entity_update_mutation_field_name = Arc::new(format!(
|
let entity_update_mutation_field_name = Arc::new(format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
entity_name, context.entity_update_mutation.mutation_suffix
|
entity_name, context.entity_update_mutation.mutation_suffix
|
||||||
));
|
));
|
||||||
let entity_update_mutation_filter_field_name =
|
|
||||||
Arc::new(context.entity_update_mutation.filter_field.clone());
|
|
||||||
let entity_update_mutation_data_field_name =
|
let entity_update_mutation_data_field_name =
|
||||||
Arc::new(context.entity_update_mutation.data_field.clone());
|
Arc::new(context.entity_update_mutation.data_field.clone());
|
||||||
let entity_query_field_name = Arc::new(entity_name);
|
|
||||||
let entity_query_filter_field_name = Arc::new(context.entity_query_field.filters.clone());
|
|
||||||
Box::new(move |context: &ResolverContext| -> GuardAction {
|
Box::new(move |context: &ResolverContext| -> GuardAction {
|
||||||
match context.ctx.data::<AuthUserInfo>() {
|
match context.ctx.data::<AuthUserInfo>() {
|
||||||
Ok(user_info) => {
|
Ok(user_info) => {
|
||||||
@ -157,43 +137,7 @@ where
|
|||||||
&column_name,
|
&column_name,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
field if field == entity_delete_mutation_field_name.as_str() => context
|
field if field == entity_update_mutation_field_name.as_str() => {
|
||||||
.args
|
|
||||||
.try_get(&entity_delete_mutation_filter_field_name)
|
|
||||||
.and_then(|filter_value| {
|
|
||||||
guard_filter_object_accessor_with_subscriber_id(
|
|
||||||
filter_value,
|
|
||||||
&column_name,
|
|
||||||
subscriber_id,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|inner_error| {
|
|
||||||
AuthError::from_graphql_subscribe_id_guard(
|
|
||||||
inner_error,
|
|
||||||
context,
|
|
||||||
&entity_delete_mutation_filter_field_name,
|
|
||||||
&column_name,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
field if field == entity_update_mutation_field_name.as_str() => context
|
|
||||||
.args
|
|
||||||
.try_get(&entity_update_mutation_filter_field_name)
|
|
||||||
.and_then(|filter_value| {
|
|
||||||
guard_filter_object_accessor_with_subscriber_id(
|
|
||||||
filter_value,
|
|
||||||
&column_name,
|
|
||||||
subscriber_id,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|inner_error| {
|
|
||||||
AuthError::from_graphql_subscribe_id_guard(
|
|
||||||
inner_error,
|
|
||||||
context,
|
|
||||||
&entity_update_mutation_filter_field_name,
|
|
||||||
&column_name,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.and_then(|_| {
|
|
||||||
match context.args.get(&entity_update_mutation_data_field_name) {
|
match context.args.get(&entity_update_mutation_data_field_name) {
|
||||||
Some(data_value) => {
|
Some(data_value) => {
|
||||||
guard_data_object_accessor_with_optional_subscriber_id(
|
guard_data_object_accessor_with_optional_subscriber_id(
|
||||||
@ -212,25 +156,7 @@ where
|
|||||||
}
|
}
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
field if field == entity_query_field_name.as_str() => context
|
|
||||||
.args
|
|
||||||
.try_get(&entity_query_filter_field_name)
|
|
||||||
.and_then(|filter_value| {
|
|
||||||
guard_filter_object_accessor_with_subscriber_id(
|
|
||||||
filter_value,
|
|
||||||
&column_name,
|
|
||||||
subscriber_id,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|inner_error| {
|
|
||||||
AuthError::from_graphql_subscribe_id_guard(
|
|
||||||
inner_error,
|
|
||||||
context,
|
|
||||||
&entity_query_filter_field_name,
|
|
||||||
&column_name,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
field => Err(AuthError::from_graphql_subscribe_id_guard(
|
field => Err(AuthError::from_graphql_subscribe_id_guard(
|
||||||
async_graphql::Error::new("unsupport graphql field"),
|
async_graphql::Error::new("unsupport graphql field"),
|
||||||
context,
|
context,
|
||||||
|
@ -4,6 +4,7 @@ pub mod guard;
|
|||||||
pub mod schema_root;
|
pub mod schema_root;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
pub mod subscriptions;
|
pub mod subscriptions;
|
||||||
|
pub mod transformer;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub use config::GraphQLConfig;
|
pub use config::GraphQLConfig;
|
||||||
|
@ -3,12 +3,12 @@ use once_cell::sync::OnceCell;
|
|||||||
use sea_orm::{DatabaseConnection, EntityTrait, Iterable};
|
use sea_orm::{DatabaseConnection, EntityTrait, Iterable};
|
||||||
use seaography::{Builder, BuilderContext, FilterType, FilterTypesMapHelper};
|
use seaography::{Builder, BuilderContext, FilterType, FilterTypesMapHelper};
|
||||||
|
|
||||||
|
use super::transformer::filter_condition_transformer;
|
||||||
use crate::graphql::{
|
use crate::graphql::{
|
||||||
extentions::AuthExtensionFactory,
|
|
||||||
filter::{
|
filter::{
|
||||||
SUBSCRIBER_ID_FILTER_INFO, init_custom_filter_info, subscriber_id_condition_function,
|
SUBSCRIBER_ID_FILTER_INFO, init_custom_filter_info, subscriber_id_condition_function,
|
||||||
},
|
},
|
||||||
guard::guard_entity_with_subscriber_id,
|
guard::{guard_entity_with_subscriber_id, guard_field_with_subscriber_id},
|
||||||
util::{get_entity_column_key, get_entity_key},
|
util::{get_entity_column_key, get_entity_key},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,9 +34,13 @@ where
|
|||||||
let entity_key = get_entity_key::<T>(context);
|
let entity_key = get_entity_key::<T>(context);
|
||||||
let entity_column_key = get_entity_column_key::<T>(context, column);
|
let entity_column_key = get_entity_column_key::<T>(context, column);
|
||||||
context.guards.entity_guards.insert(
|
context.guards.entity_guards.insert(
|
||||||
entity_key,
|
entity_key.clone(),
|
||||||
guard_entity_with_subscriber_id::<T>(context, column),
|
guard_entity_with_subscriber_id::<T>(context, column),
|
||||||
);
|
);
|
||||||
|
context.guards.field_guards.insert(
|
||||||
|
entity_column_key.clone(),
|
||||||
|
guard_field_with_subscriber_id::<T>(context, column),
|
||||||
|
);
|
||||||
context.filter_types.overwrites.insert(
|
context.filter_types.overwrites.insert(
|
||||||
entity_column_key.clone(),
|
entity_column_key.clone(),
|
||||||
Some(FilterType::Custom(
|
Some(FilterType::Custom(
|
||||||
@ -47,6 +51,10 @@ where
|
|||||||
entity_column_key,
|
entity_column_key,
|
||||||
subscriber_id_condition_function::<T>(context, column),
|
subscriber_id_condition_function::<T>(context, column),
|
||||||
);
|
);
|
||||||
|
context.transformers.filter_conditions_transformers.insert(
|
||||||
|
entity_key,
|
||||||
|
filter_condition_transformer::<T>(context, column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schema(
|
pub fn schema(
|
||||||
@ -156,9 +164,6 @@ pub fn schema(
|
|||||||
};
|
};
|
||||||
schema
|
schema
|
||||||
.data(database)
|
.data(database)
|
||||||
.extension(AuthExtensionFactory {
|
|
||||||
builder_context: context,
|
|
||||||
})
|
|
||||||
.finish()
|
.finish()
|
||||||
.inspect_err(|e| tracing::error!(e = ?e))
|
.inspect_err(|e| tracing::error!(e = ?e))
|
||||||
}
|
}
|
||||||
|
27
apps/recorder/src/graphql/transformer.rs
Normal file
27
apps/recorder/src/graphql/transformer.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use async_graphql::dynamic::ResolverContext;
|
||||||
|
use sea_orm::{ColumnTrait, Condition, EntityTrait};
|
||||||
|
use seaography::{BuilderContext, FnFilterConditionsTransformer};
|
||||||
|
|
||||||
|
use crate::auth::AuthUserInfo;
|
||||||
|
|
||||||
|
pub fn filter_condition_transformer<T>(
|
||||||
|
_context: &BuilderContext,
|
||||||
|
column: &T::Column,
|
||||||
|
) -> FnFilterConditionsTransformer
|
||||||
|
where
|
||||||
|
T: EntityTrait,
|
||||||
|
<T as EntityTrait>::Model: Sync,
|
||||||
|
{
|
||||||
|
let column = *column;
|
||||||
|
Box::new(
|
||||||
|
move |context: &ResolverContext, condition: Condition| -> Condition {
|
||||||
|
match context.ctx.data::<AuthUserInfo>() {
|
||||||
|
Ok(user_info) => {
|
||||||
|
let subscriber_id = user_info.subscriber_auth.subscriber_id;
|
||||||
|
condition.add(column.eq(subscriber_id))
|
||||||
|
}
|
||||||
|
Err(err) => unreachable!("auth user info must be guarded: {:?}", err),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user