refactor: extract session_id extraction helper, DRY auth.rs
Extract duplicated session ID extraction + validation logic from SessionAuthMiddleware::call() and require_session() into two shared helper functions: extract_session_id and validate_and_build_identity. Removes ~60 lines of duplicated code while preserving behavior: - Both call sites now rely on the same extraction/validation path - User-Agent default remains empty string (existing behavior unchanged) - Error response format (401 with header/validation messages) unchanged Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7d8487cefb
commit
e32501ee59
@@ -115,6 +115,52 @@ pub struct SessionAuthMiddleware<S> {
|
||||
store: Arc<Store>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Session ID helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Extract and validate `X-Session-Id` from request headers.
|
||||
///
|
||||
/// Flow: read header -> validate non-empty -> return ID or a 401 error response.
|
||||
fn extract_session_id<ReqBody>(req: &Request<ReqBody>) -> Result<String, Response> {
|
||||
let session_id = req
|
||||
.headers()
|
||||
.get("X-Session-Id")
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
match session_id {
|
||||
Some(id) if !id.is_empty() => Ok(id),
|
||||
_ => Err((StatusCode::UNAUTHORIZED, "missing X-Session-Id header").into_response()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate session and build identity from request context.
|
||||
///
|
||||
/// Flow: validate session in store -> extract User-Agent -> build SessionIdentity.
|
||||
fn validate_and_build_identity<ReqBody>(
|
||||
session_id: &str,
|
||||
store: &Store,
|
||||
req: &Request<ReqBody>,
|
||||
) -> Result<SessionIdentity, Response> {
|
||||
match validate_session(session_id, store) {
|
||||
Ok(_session) => {
|
||||
let user_agent = req
|
||||
.headers()
|
||||
.get(header::USER_AGENT)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
Ok(SessionIdentity::new(session_id.to_string(), user_agent))
|
||||
}
|
||||
Err(e) => Err((
|
||||
StatusCode::UNAUTHORIZED,
|
||||
format!("session validation failed: {e}"),
|
||||
)
|
||||
.into_response()),
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, ReqBody> Service<Request<ReqBody>> for SessionAuthMiddleware<S>
|
||||
where
|
||||
S: Service<Request<ReqBody>, Response = Response> + Send + 'static,
|
||||
@@ -133,39 +179,17 @@ where
|
||||
fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
|
||||
let store = Arc::clone(&self.store);
|
||||
|
||||
// Extract session id from header.
|
||||
let session_id = req
|
||||
.headers()
|
||||
.get("X-Session-Id")
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
let session_id = match session_id {
|
||||
Some(id) if !id.is_empty() => id,
|
||||
_ => {
|
||||
let resp =
|
||||
(StatusCode::UNAUTHORIZED, "missing X-Session-Id header").into_response();
|
||||
return Box::pin(async move { Ok(resp) });
|
||||
}
|
||||
let session_id = match extract_session_id(&req) {
|
||||
Ok(id) => id,
|
||||
Err(resp) => return Box::pin(async move { Ok(resp) }),
|
||||
};
|
||||
|
||||
// Validate session.
|
||||
if let Err(e) = validate_session(&session_id, &store) {
|
||||
let resp = (
|
||||
StatusCode::UNAUTHORIZED,
|
||||
format!("session validation failed: {e}"),
|
||||
)
|
||||
.into_response();
|
||||
return Box::pin(async move { Ok(resp) });
|
||||
}
|
||||
let user_agent = req
|
||||
.headers()
|
||||
.get(header::USER_AGENT)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
let identity = SessionIdentity::new(session_id, user_agent);
|
||||
req.extensions_mut().insert(identity);
|
||||
match validate_and_build_identity(&session_id, &store, &req) {
|
||||
Ok(identity) => {
|
||||
req.extensions_mut().insert(identity);
|
||||
}
|
||||
Err(resp) => return Box::pin(async move { Ok(resp) }),
|
||||
};
|
||||
|
||||
let fut = self.inner.call(req);
|
||||
Box::pin(fut)
|
||||
@@ -186,33 +210,15 @@ pub async fn require_session(
|
||||
mut req: Request<axum::body::Body>,
|
||||
next: axum::middleware::Next,
|
||||
) -> Response {
|
||||
let session_id = req
|
||||
.headers()
|
||||
.get("X-Session-Id")
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
let session_id = match session_id {
|
||||
Some(id) if !id.is_empty() => id,
|
||||
_ => {
|
||||
return (StatusCode::UNAUTHORIZED, "missing X-Session-Id header").into_response();
|
||||
}
|
||||
let session_id = match extract_session_id(&req) {
|
||||
Ok(id) => id,
|
||||
Err(resp) => return resp,
|
||||
};
|
||||
|
||||
if let Err(e) = validate_session(&session_id, &store) {
|
||||
return (
|
||||
StatusCode::UNAUTHORIZED,
|
||||
format!("session validation failed: {e}"),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
let user_agent = req
|
||||
.headers()
|
||||
.get(header::USER_AGENT)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
let identity = SessionIdentity::new(session_id, user_agent);
|
||||
let identity = match validate_and_build_identity(&session_id, &store, &req) {
|
||||
Ok(identity) => identity,
|
||||
Err(resp) => return resp,
|
||||
};
|
||||
req.extensions_mut().insert(identity);
|
||||
next.run(req).await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user