feat: implement basic auth in middleware
							parent
							
								
									993e58babf
								
							
						
					
					
						commit
						22e01d10dc
					
				|  | @ -1,7 +1,10 @@ | |||
| use axum::{ | ||||
|     extract::{Path, State}, | ||||
|     extract::{Path, Request, State}, | ||||
|     http::StatusCode, | ||||
|     middleware::Next, | ||||
|     response::{IntoResponse, Response}, | ||||
|     routing::post, | ||||
|     Router, | ||||
|     RequestExt, Router, | ||||
| }; | ||||
| use axum_extra::{ | ||||
|     extract::{ | ||||
|  | @ -69,7 +72,7 @@ async fn post_logout( | |||
| 
 | ||||
|         tokio::task::spawn_blocking(move || { | ||||
|             if let Some(session) = Session::by_id(&ctx.pool, session_id)? { | ||||
|                 let user = session.user(&ctx.pool)?; | ||||
|                 let user = session.user(&ctx.pool)?.ok_or(AppError::NotFound)?; | ||||
| 
 | ||||
|                 // The requested user to logout should be the same as the one linked to the session
 | ||||
|                 // ID
 | ||||
|  | @ -90,3 +93,74 @@ async fn post_logout( | |||
|         Ok(jar) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// This middleware accepts
 | ||||
| pub async fn auth_middleware(State(ctx): State<Context>, mut req: Request, next: Next) -> Response { | ||||
|     // SAFETY: this extractor's error type is Infallible
 | ||||
|     let jar: CookieJar = req.extract_parts().await.unwrap(); | ||||
|     tracing::debug!("{:?}", jar); | ||||
|     let mut auth_user = None; | ||||
|     let mut new_session_id = None; | ||||
| 
 | ||||
|     if let Some(session_id) = jar | ||||
|         .get(SESSION_ID_COOKIE) | ||||
|         .and_then(|c| c.value().parse::<i64>().ok()) | ||||
|     { | ||||
|         match tokio::task::spawn_blocking(move || Session::user_from_id(&ctx.pool, session_id)) | ||||
|             .await | ||||
|             .unwrap() | ||||
|             .map_err(AppError::Db) | ||||
|         { | ||||
|             Ok(user) => { | ||||
|                 auth_user = user; | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 return err.into_response(); | ||||
|             } | ||||
|         }; | ||||
|     } else if let Ok(auth) = req | ||||
|         .extract_parts::<TypedHeader<Authorization<Basic>>>() | ||||
|         .await | ||||
|     { | ||||
|         match tokio::task::spawn_blocking(move || { | ||||
|             let user = User::by_username(&ctx.pool, auth.username())?.ok_or(AppError::NotFound)?; | ||||
| 
 | ||||
|             if user.verify_password(auth.password()) { | ||||
|                 Ok((Session::new_for_user(&ctx.pool, user.id)?, user)) | ||||
|             } else { | ||||
|                 Err(AppError::Unauthorized) | ||||
|             } | ||||
|         }) | ||||
|         .await | ||||
|         .unwrap() | ||||
|         { | ||||
|             Ok((session, user)) => { | ||||
|                 auth_user = Some(user); | ||||
|                 new_session_id = Some(session.id); | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 return err.into_response(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if let Some(user) = auth_user { | ||||
|         req.extensions_mut().insert(user); | ||||
|         let res = next.run(req).await; | ||||
| 
 | ||||
|         if let Some(session_id) = new_session_id { | ||||
|             ( | ||||
|                 jar.add( | ||||
|                     Cookie::build((SESSION_ID_COOKIE, session_id.to_string())) | ||||
|                         .expires(Expiration::Session), | ||||
|                 ), | ||||
|                 res, | ||||
|             ) | ||||
|                 .into_response() | ||||
|         } else { | ||||
|             res | ||||
|         } | ||||
|     } else { | ||||
|         StatusCode::UNAUTHORIZED.into_response() | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue