mockforge_collab/
middleware.rs1use crate::auth::AuthService;
4use crate::error::CollabError;
5use axum::{
6 extract::{Request, State},
7 http::StatusCode,
8 middleware::Next,
9 response::Response,
10};
11use std::sync::Arc;
12use uuid::Uuid;
13
14#[derive(Clone, Debug)]
16pub struct AuthUser {
17 pub user_id: Uuid,
18 pub username: String,
19}
20
21pub async fn auth_middleware(
23 State(auth): State<Arc<AuthService>>,
24 mut request: Request,
25 next: Next,
26) -> Result<Response, (StatusCode, String)> {
27 let auth_header = request
29 .headers()
30 .get("Authorization")
31 .and_then(|h| h.to_str().ok())
32 .ok_or_else(|| (StatusCode::UNAUTHORIZED, "Missing Authorization header".to_string()))?;
33
34 let token = auth_header.strip_prefix("Bearer ").ok_or_else(|| {
36 (StatusCode::UNAUTHORIZED, "Invalid Authorization header format".to_string())
37 })?;
38
39 let claims = auth
41 .verify_token(token)
42 .map_err(|e| (StatusCode::UNAUTHORIZED, format!("Invalid token: {}", e)))?;
43
44 let user_id = Uuid::parse_str(&claims.sub)
46 .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Invalid user ID in token".to_string()))?;
47
48 request.extensions_mut().insert(AuthUser {
50 user_id,
51 username: claims.username,
52 });
53
54 Ok(next.run(request).await)
55}
56
57pub fn extract_auth_user(request: &Request) -> Result<&AuthUser, CollabError> {
59 request
60 .extensions()
61 .get::<AuthUser>()
62 .ok_or_else(|| CollabError::AuthenticationFailed("Not authenticated".to_string()))
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_auth_user_creation() {
71 let user = AuthUser {
72 user_id: Uuid::new_v4(),
73 username: "testuser".to_string(),
74 };
75
76 assert_eq!(user.username, "testuser");
77 }
78}