From c4d374dbfe8345c996424cd6c3a585a021f1261e Mon Sep 17 00:00:00 2001 From: schn33fuchs Date: Sat, 25 Apr 2026 13:21:31 +0200 Subject: [PATCH] Added token validation --- backend/src/cookie/mod.rs | 1 + backend/src/cookie/validation.rs | 84 ++++++++++++++++++++++++++++++++ backend/src/models.rs | 2 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 backend/src/cookie/validation.rs diff --git a/backend/src/cookie/mod.rs b/backend/src/cookie/mod.rs index 417233c..a20d7b2 100644 --- a/backend/src/cookie/mod.rs +++ b/backend/src/cookie/mod.rs @@ -1 +1,2 @@ pub mod jwt; +pub mod validation; diff --git a/backend/src/cookie/validation.rs b/backend/src/cookie/validation.rs new file mode 100644 index 0000000..3d7a4ad --- /dev/null +++ b/backend/src/cookie/validation.rs @@ -0,0 +1,84 @@ +use std::sync::Arc; + +use axum::{ + Json, + body::Body, + extract::State, + http::{Request, StatusCode, header}, + middleware::Next, + response::IntoResponse, +}; +use axum_extra::extract::CookieJar; +use jsonwebtoken::DecodingKey; +use serde_json::json; + +use crate::{AppState, cookie::jwt::decode_token, models::LoginModel}; + +pub async fn validate_token( + cookies: CookieJar, + State(data): State>, + mut request: Request, + next: Next, +) -> Result)> { + let token = cookies + .get("token") + .map(|cookie| cookie.value().to_string()) + .or_else(|| { + request + .headers() + .get(header::AUTHORIZATION) + .and_then(|header| header.to_str().ok()) + .and_then(|value| { + if value.starts_with("Bearer ") { + Some(value[7..].to_owned()) + } else { + None + } + }) + }); + + let token = token.ok_or_else(|| { + let error = json!({ + "status": "error", + "message": "Please provide a valid token" + }); + (StatusCode::UNAUTHORIZED, Json(error)) + })?; + + let claims = decode_token( + token, + &DecodingKey::from_secret(data.env.token_secret.as_ref()), + ) + .unwrap(); + + let uuid = (&claims.subject).parse::().map_err(|_| { + let error = json!({ + "status": "error", + "message": "Invalid user id" + }); + (StatusCode::UNAUTHORIZED, Json(error)) + })?; + + let user = sqlx::query_as::<_, LoginModel>(r#"SELECT * FROM users WHERE id = $1"#) + .bind(uuid) + .fetch_optional(&data.db) + .await + .map_err(|e| { + let error = json!({ + "status": "error", + "message": format!("Database error: {}", e) + }); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error)) + })?; + + let user = user.ok_or_else(|| { + let error = json!({ + "status": "error", + "message": "Invalid user" + }); + (StatusCode::UNAUTHORIZED, Json(error)) + })?; + + request.extensions_mut().insert(user); + Ok(next.run(request).await) +} diff --git a/backend/src/models.rs b/backend/src/models.rs index 0a5baac..113f14b 100644 --- a/backend/src/models.rs +++ b/backend/src/models.rs @@ -64,7 +64,7 @@ pub struct LoginScheme { pub pwd: String, } -#[derive(Deserialize, Serialize, Debug, sqlx::FromRow)] +#[derive(Deserialize, Serialize, Debug, Clone, sqlx::FromRow)] pub struct LoginModel { pub id: i16, pub last_name: String,