fix(auth): make AuthenticatedUser extractor perform authentication directly
Co-authored-by: jnsgruk <668505+jnsgruk@users.noreply.github.com>
This commit is contained in:
parent
5f4cbf5294
commit
5c05f35a59
1 changed files with 53 additions and 10 deletions
|
|
@ -15,18 +15,61 @@ use crate::server::server::AppState;
|
|||
pub struct AuthenticatedUser(pub User);
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for AuthenticatedUser
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
impl FromRequestParts<AppState> for AuthenticatedUser {
|
||||
type Rejection = StatusCode;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
parts
|
||||
.extensions
|
||||
.get::<AuthenticatedUser>()
|
||||
.cloned()
|
||||
.ok_or(StatusCode::UNAUTHORIZED)
|
||||
async fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &AppState,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
// Try to get from extensions first (if middleware already set it)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue