fix(auth): make AuthenticatedUser extractor perform authentication directly

Co-authored-by: jnsgruk <668505+jnsgruk@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-11-25 10:32:11 +00:00 committed by Jon Seager
parent 5f4cbf5294
commit 5c05f35a59
No known key found for this signature in database

View file

@ -15,18 +15,61 @@ use crate::server::server::AppState;
pub struct AuthenticatedUser(pub User); pub struct AuthenticatedUser(pub User);
#[async_trait] #[async_trait]
impl<S> FromRequestParts<S> for AuthenticatedUser impl FromRequestParts<AppState> for AuthenticatedUser {
where
S: Send + Sync,
{
type Rejection = StatusCode; type Rejection = StatusCode;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> { async fn from_request_parts(
parts parts: &mut Parts,
.extensions state: &AppState,
.get::<AuthenticatedUser>() ) -> Result<Self, Self::Rejection> {
.cloned() // Try to get from extensions first (if middleware already set it)
.ok_or(StatusCode::UNAUTHORIZED) if let Some(user) = parts.extensions.get::<AuthenticatedUser>() {
return Ok(user.clone());
}
// Otherwise, extract from Authorization header directly
let auth_header = parts
.headers
.get(header::AUTHORIZATION)
.ok_or(StatusCode::UNAUTHORIZED)?;
let auth_str = auth_header.to_str().map_err(|_| StatusCode::UNAUTHORIZED)?;
// Check for "Bearer <token>" format
let token = auth_str
.strip_prefix("Bearer ")
.ok_or(StatusCode::UNAUTHORIZED)?;
// Hash the token to look it up in the database
let token_hash = hash_token(token);
// Look up the token
let token_record = state
.token_repo
.get_by_token_hash(&token_hash)
.await
.map_err(|_| StatusCode::UNAUTHORIZED)?;
// Check if token is revoked
if token_record.is_revoked() {
return Err(StatusCode::UNAUTHORIZED);
}
// Update last used timestamp (fire and forget)
let token_repo = state.token_repo.clone();
let token_id = token_record.id.clone();
tokio::spawn(async move {
let _ = token_repo.update_last_used(token_id).await;
});
// Get the user
let user = state
.user_repo
.get(token_record.user_id)
.await
.map_err(|_| StatusCode::UNAUTHORIZED)?;
Ok(AuthenticatedUser(user))
} }
} }