admin_extractor.rs
70 lignes · 2270 octets
/// Admin Claims Extractor /// Feature 009: Admin & Settings /// /// Custom extractor that ensures the user is authenticated and has admin role. /// Returns 403 Forbidden if user is not an admin. /// /// This extractor reads Claims from request extensions (added by admin_required middleware). /// The middleware must be applied to routes using this extractor. use axum::{ extract::FromRequestParts, http::request::Parts, response::{IntoResponse, Response}, }; use crate::auth::jwt::Claims; /// Extract admin claims from request /// /// This extractor ensures the user is authenticated and has admin role. /// It reads Claims from request extensions (added by admin_required middleware). /// If Claims are not in extensions, middleware didn't run - redirect to login. /// If authenticated but not admin, returns 403 Forbidden. /// /// # Usage /// /// ```rust,ignore /// pub async fn admin_handler( /// AdminClaims(claims): AdminClaims, /// State(db): State<DatabaseConnection>, /// ) -> Result<impl IntoResponse, AppError> { /// // Handler code /// } /// ``` #[derive(Clone, Debug)] pub struct AdminClaims(pub Claims); impl<S> FromRequestParts<S> for AdminClaims where S: Send + Sync, { type Rejection = Response; async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> { // Get Claims from extensions (added by admin_required middleware) let claims = parts.extensions.get::<Claims>().ok_or_else(|| { // Claims absent → the auth middleware did not run for this route. crate::middleware::auth_service::auth_failure_from_extensions( &parts.extensions, &parts.uri, ) })?; // Verify admin role if !claims.roles.contains(&"admin".to_string()) { let uri = parts.uri.clone(); tracing::warn!( "Non-admin user {} attempted to access admin route: {}", claims.sub, uri ); return Err(( axum::http::StatusCode::FORBIDDEN, "Access denied: Admin role required", ) .into_response()); } Ok(AdminClaims(claims.clone())) } }
GitRust