Skip to main content

cloudillo_core/
extract.rs

1//! Custom extractors for Cloudillo-specific data
2
3use async_trait::async_trait;
4use axum::extract::FromRequestParts;
5use axum::http::request::Parts;
6
7use crate::app::AppState;
8use crate::prelude::*;
9use cloudillo_types::auth_adapter;
10
11// Re-export IdTag and TnIdResolver from cloudillo-types
12pub use cloudillo_types::extract::{IdTag, TnIdResolver};
13
14// Implement TnIdResolver for AppState so TnId can be extracted from requests.
15// The blanket impl `TnIdResolver for Arc<T>` in cloudillo-types makes this
16// work for `App = Arc<AppState>` automatically.
17#[async_trait]
18impl TnIdResolver for AppState {
19	async fn resolve_tn_id(&self, id_tag: &str) -> Result<TnId, Error> {
20		self.auth_adapter.read_tn_id(id_tag).await.map_err(|_| Error::PermissionDenied)
21	}
22}
23
24// Auth //
25//******//
26#[derive(Debug, Clone)]
27pub struct Auth(pub auth_adapter::AuthCtx);
28
29impl<S> FromRequestParts<S> for Auth
30where
31	S: Send + Sync,
32{
33	type Rejection = Error;
34
35	async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
36		if let Some(auth) = parts.extensions.get::<Auth>().cloned() {
37			Ok(auth)
38		} else {
39			Err(Error::PermissionDenied)
40		}
41	}
42}
43
44// OptionalAuth //
45//***************//
46/// Optional auth extractor that doesn't fail if auth is missing
47#[derive(Debug, Clone)]
48pub struct OptionalAuth(pub Option<auth_adapter::AuthCtx>);
49
50impl<S> FromRequestParts<S> for OptionalAuth
51where
52	S: Send + Sync,
53{
54	type Rejection = Error;
55
56	async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
57		let auth = parts.extensions.get::<Auth>().cloned().map(|a| a.0);
58		Ok(OptionalAuth(auth))
59	}
60}
61
62// RequestId //
63//***********//
64/// Request ID for tracing and debugging
65#[derive(Clone, Debug)]
66pub struct RequestId(pub String);
67
68/// Optional Request ID extractor - always succeeds, returns None if not available
69#[derive(Clone, Debug)]
70pub struct OptionalRequestId(pub Option<String>);
71
72impl<S> FromRequestParts<S> for OptionalRequestId
73where
74	S: Send + Sync,
75{
76	type Rejection = Error;
77
78	async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
79		let req_id = parts.extensions.get::<RequestId>().map(|r| r.0.clone());
80		Ok(OptionalRequestId(req_id))
81	}
82}
83
84// vim: ts=4