Skip to main content

reinhardt_auth/
auth_info.rs

1//! Lightweight authentication extractor that reads from request extensions.
2//!
3//! Does NOT perform a database query. Use [`AuthUser`](crate::AuthUser) when the full
4//! user model object is needed.
5
6use async_trait::async_trait;
7use reinhardt_di::{DiError, DiResult, Injectable, InjectionContext};
8use reinhardt_http::AuthState;
9
10/// Lightweight authentication extractor that reads from request extensions.
11///
12/// Wraps `AuthState` as a tuple struct for destructuring, consistent
13/// with `Path<T>`, `Json<T>`, and other Reinhardt extractors.
14///
15/// Requires `feature = "params"` to access request data from `InjectionContext`.
16///
17/// # Usage
18///
19/// ```rust,ignore
20/// use reinhardt_auth::AuthInfo;
21///
22/// #[get("/admin/")]
23/// pub async fn admin(
24///     #[inject] AuthInfo(state): AuthInfo,
25/// ) -> ViewResult<Response> {
26///     if !state.is_admin() {
27///         return Err(Error::forbidden("Admin access required"));
28///     }
29///     // ...
30/// }
31/// ```
32///
33/// # Failure
34///
35/// Returns an injection error (maps to HTTP 401) when:
36/// - No `AuthState` is present in request extensions
37/// - `AuthState` indicates the user is not authenticated
38#[derive(Debug, Clone)]
39pub struct AuthInfo(pub AuthState);
40
41#[cfg(feature = "params")]
42#[async_trait]
43impl Injectable for AuthInfo {
44	async fn inject(ctx: &InjectionContext) -> DiResult<Self> {
45		let request = ctx.get_http_request().ok_or_else(|| {
46			DiError::NotFound(
47				"AuthInfo: No HTTP request available in InjectionContext. \
48				 Ensure the router is configured with .with_di_context()"
49					.to_string(),
50			)
51		})?;
52
53		let auth_state: AuthState = request.extensions.get().ok_or_else(|| {
54			DiError::NotFound(
55				"AuthInfo: No AuthState found in request extensions. \
56				 Ensure authentication middleware is configured."
57					.to_string(),
58			)
59		})?;
60
61		if !auth_state.is_authenticated() {
62			return Err(DiError::NotFound(
63				"AuthInfo: User is not authenticated".to_string(),
64			));
65		}
66
67		Ok(AuthInfo(auth_state))
68	}
69}
70
71#[cfg(not(feature = "params"))]
72#[async_trait]
73impl Injectable for AuthInfo {
74	async fn inject(_ctx: &InjectionContext) -> DiResult<Self> {
75		Err(DiError::NotFound(
76			"AuthInfo requires the 'params' feature to be enabled".to_string(),
77		))
78	}
79}