graphql_starter/graphql/
guard.rs1use std::marker::PhantomData;
2
3use async_graphql::{Context, Guard, Result};
4
5use crate::{
6 auth::{AuthErrorCode, AuthState, AuthorizationService, Subject},
7 error::{err, GraphQLError},
8};
9
10pub struct AuthGuard<S: Subject, St: AuthState<S>> {
15 relation: &'static str,
16 object: &'static str,
17 sub_type: PhantomData<S>,
19 state_type: PhantomData<St>,
20}
21
22impl<S: Subject, St: AuthState<S>> AuthGuard<S, St> {
23 pub fn new(relation: &'static str, object: &'static str) -> Self {
25 AuthGuard {
26 relation,
27 object,
28 sub_type: PhantomData,
29 state_type: PhantomData,
30 }
31 }
32}
33
34impl<S: Subject, St: AuthState<S>> Guard for AuthGuard<S, St> {
35 async fn check(&self, ctx: &Context<'_>) -> Result<()> {
36 let sub = ctx.data::<Option<S>>().map_err(Box::<GraphQLError>::from)?.as_ref();
37 match sub {
38 Some(sub) => {
39 let state = ctx.data::<St>().map_err(Box::<GraphQLError>::from)?;
40 Ok(state.authz().authorize(sub, self.relation, self.object).await?)
41 }
42 None => Err(
43 GraphQLError::from_err(err!(AuthErrorCode::AuthMissing, "The subject must be authenticated")).into(),
44 ),
45 }
46 }
47}