From f4765630ee358984ee28a4e1c956edb705292704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Fri, 24 Jan 2025 04:15:06 +0300 Subject: [PATCH] feat: :sparkles: user_and_token middleware refactor: :recycle: getting otp from client --- src/feature/auth.rs | 11 ++++---- src/routing/login.rs | 33 +++++++++++++--------- src/routing/middleware.rs | 58 +++++++++++++++++++++++++++++---------- src/routing/user.rs | 31 +++++++++++---------- 4 files changed, 86 insertions(+), 47 deletions(-) diff --git a/src/feature/auth.rs b/src/feature/auth.rs index b751db3..fa71f51 100644 --- a/src/feature/auth.rs +++ b/src/feature/auth.rs @@ -5,7 +5,7 @@ use tokio::sync::RwLock; use crate::{ error::ForumMailError, - mail::{MailFieldsOneTimePassword, MailTemplate}, + //mail::{MailFieldsOneTimePassword, MailTemplate}, }; use super::user::User; @@ -31,10 +31,11 @@ impl OneTimePassword { one_time_password, }; - let mail_template = - MailTemplate::OneTimePassword(MailFieldsOneTimePassword::new(&user.name, &new_self)); - - mail_template.send_mail(user_email).await?; + //todo vice versa comments :D + // let mail_template = + // MailTemplate::OneTimePassword(MailFieldsOneTimePassword::new(&user.name, &new_self)); + println!("{}", user_email); + //mail_template.send_mail(user_email).await?; let mut one_time_passwords = ONE_TIME_PASSWORDS.write().await; one_time_passwords.push(new_self); diff --git a/src/routing/login.rs b/src/routing/login.rs index 6fd5e90..526d851 100644 --- a/src/routing/login.rs +++ b/src/routing/login.rs @@ -1,14 +1,18 @@ +use std::sync::Arc; + use axum::{ extract::Path, http::StatusCode, response::IntoResponse, routing::{delete, get, patch, post}, - Json, Router, + Extension, Json, Router, }; use serde::{Deserialize, Serialize}; use crate::feature::{auth::OneTimePassword, login::Login, user::User, user_contact::UserContact}; +use super::middleware::{self, UserAndToken}; + const CONTACT_EMAIL_DEFAULT_ID: i64 = 0; #[derive(Debug, Serialize, Deserialize)] @@ -18,13 +22,8 @@ struct CreateOneTimePassword { #[derive(Debug, Serialize, Deserialize)] struct CreateLogin { - pub one_time_password: OneTimePassword, -} - -#[derive(Debug, Serialize, Deserialize)] -struct UpdateLogin { - pub user_id: i64, - pub token: String, + user_id: i64, + one_time_password: String, } pub fn route() -> Router { @@ -32,7 +31,10 @@ pub fn route() -> Router { .route("/one_time_password", post(create_one_time_password)) .route("/", post(create)) .route("/users/{user_id}/tokens/{token}", get(read)) - .route("/", patch(update)) + .route( + "/", + patch(update).route_layer(axum::middleware::from_fn(middleware::user_and_token)), + ) .route("/users/{user_id}/tokens/{token}", delete(delete_)) .route("/users/{user_id}", get(read_all_for_user)) .route("/users/{user_id}", delete(delete_all_for_user)) @@ -58,8 +60,13 @@ async fn create_one_time_password( } } async fn create(Json(create_login): Json) -> impl IntoResponse { - match OneTimePassword::verify(&create_login.one_time_password).await { - true => match Login::create(&create_login.one_time_password.user_id).await { + let one_time_password = OneTimePassword { + user_id: create_login.user_id, + one_time_password: create_login.one_time_password, + }; + + match OneTimePassword::verify(&one_time_password).await { + true => match Login::create(&one_time_password.user_id).await { Ok(login) => (StatusCode::CREATED, Json(serde_json::json!(login))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -85,8 +92,8 @@ async fn read(Path((user_id, token)): Path<(i64, String)>) -> impl IntoResponse } } -async fn update(Json(update_login): Json) -> impl IntoResponse { - match Login::update(&update_login.user_id, &update_login.token).await { +async fn update(Extension(user_and_token): Extension>) -> impl IntoResponse { + match Login::update(&user_and_token.user.user_id, &user_and_token.token).await { Ok(login) => (StatusCode::ACCEPTED, Json(serde_json::json!(login))), Err(err_val) => ( StatusCode::BAD_REQUEST, diff --git a/src/routing/middleware.rs b/src/routing/middleware.rs index d55a5fa..7c326f6 100644 --- a/src/routing/middleware.rs +++ b/src/routing/middleware.rs @@ -3,10 +3,11 @@ use std::sync::Arc; use axum::{ body::{to_bytes, Body}, extract::Request, - http::{self, Method, StatusCode}, + http::{self, HeaderMap, Method, StatusCode}, middleware::Next, response::IntoResponse, }; +use serde::{Deserialize, Serialize}; use crate::feature::{login::TokenMeta, user::User}; @@ -29,22 +30,18 @@ struct UserAndTargetUserAndRequest { request: Request, } -async fn user_extraction(request: Request) -> Option { - if let Some(authorization_header) = request.headers().get(http::header::AUTHORIZATION) { +#[derive(Debug, Serialize, Deserialize)] +pub struct UserAndToken { + pub user: User, + pub token: String, +} + +async fn authorization_token_extraction(request_headers: &HeaderMap) -> Option { + if let Some(authorization_header) = request_headers.get(http::header::AUTHORIZATION) { if let Ok(authorization_header) = authorization_header.to_str() { - if let Some((bearer, authorization_header)) = authorization_header.split_once(' ') { + if let Some((bearer, authorization_token)) = authorization_header.split_once(' ') { if bearer.to_lowercase() == "bearer" { - match TokenMeta::verify_token(&authorization_header.to_string()).await { - Ok(claims) => { - return Some(UserAndRequest { - user: User::read(&claims.custom.user_id).await.ok()?, - request, - }); - } - Err(err_val) => { - eprintln!("Verify Token | {}", err_val); - } - } + return Some(authorization_token.to_owned()); } } } @@ -52,6 +49,23 @@ async fn user_extraction(request: Request) -> Option { None } +async fn user_extraction(request: Request) -> Option { + if let Some(authorization_token) = authorization_token_extraction(&request.headers()).await { + match TokenMeta::verify_token(&authorization_token.to_string()).await { + Ok(claims) => { + return Some(UserAndRequest { + user: User::read(&claims.custom.user_id).await.ok()?, + request, + }); + } + Err(err_val) => { + eprintln!("Verify Token | {}", err_val); + } + } + } + None +} + async fn target_user_extraction_from_uri(request: Request) -> Option { let uri_parts = request.uri().path().split('/').collect::>(); for (index, uri_part) in uri_parts.iter().enumerate() { @@ -213,3 +227,17 @@ pub async fn pass_higher_or_self( } Err(StatusCode::FORBIDDEN) } + +pub async fn user_and_token(request: Request, next: Next) -> Result { + if let Some(token) = authorization_token_extraction(&request.headers()).await { + if let Some(user_and_request) = user_extraction(request).await { + let user = user_and_request.user; + let mut request = user_and_request.request; + let user_and_token = Arc::new(UserAndToken { user, token }); + + request.extensions_mut().insert(user_and_token); + return Ok(next.run(request).await); + } + } + Err(StatusCode::FORBIDDEN) +} diff --git a/src/routing/user.rs b/src/routing/user.rs index f197914..2856852 100644 --- a/src/routing/user.rs +++ b/src/routing/user.rs @@ -22,7 +22,7 @@ struct CreateUser { #[derive(Debug, Serialize, Deserialize)] struct UpdateUser { - id: i64, + user_id: i64, name: String, surname: String, gender: bool, @@ -34,7 +34,7 @@ pub fn route() -> Router { Router::new() .route("/", post(create)) .route( - "/{id}", + "/{user_id}", get(read).route_layer(axum::middleware::from_fn(middleware::pass)), ) .route( @@ -42,7 +42,7 @@ pub fn route() -> Router { patch(update).route_layer(axum::middleware::from_fn(middleware::pass_higher_or_self)), ) .route( - "/{id}", + "/{user_id}", delete(delete_).route_layer(axum::middleware::from_fn(middleware::pass_higher_or_self)), ) .route( @@ -54,15 +54,18 @@ pub fn route() -> Router { .route("/birth_dates/{birth_date}", get(read_all_for_birth_date)) .route("/roles/{role}", get(read_all_for_role)) .route("/genders/{gender}", get(read_all_for_gender)) - .route("/ids", get(read_all_id)) - .route("/ids/names/{name}", get(read_all_id_for_name)) - .route("/ids/surnames/{surname}", get(read_all_id_for_surname)) + .route("/users_ids", get(read_all_id)) + .route("/users_ids/names/{name}", get(read_all_id_for_name)) .route( - "/ids/birth_dates/{birth_date}", + "/users_ids/surnames/{surname}", + get(read_all_id_for_surname), + ) + .route( + "/users_ids/birth_dates/{birth_date}", get(read_all_id_for_birth_date), ) - .route("/ids/roles/{role}", get(read_all_id_for_role)) - .route("/ids/genders/{gender}", get(read_all_id_for_gender)) + .route("/users_ids/roles/{role}", get(read_all_id_for_role)) + .route("/users_ids/genders/{gender}", get(read_all_id_for_gender)) .route("/count", get(count_all)) .route("/count/names/{name}", get(count_all_for_name)) .route("/count/surnames/{surname}", get(count_all_for_surname)) @@ -91,8 +94,8 @@ async fn create(Json(create_user): Json) -> impl IntoResponse { } } -async fn read(Path(id): Path) -> impl IntoResponse { - match User::read(&id).await { +async fn read(Path(user_id): Path) -> impl IntoResponse { + match User::read(&user_id).await { Ok(user) => (StatusCode::OK, Json(serde_json::json!(user))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -103,7 +106,7 @@ async fn read(Path(id): Path) -> impl IntoResponse { async fn update(Json(update_user): Json) -> impl IntoResponse { match User::update( - &update_user.id, + &update_user.user_id, &update_user.name, &update_user.surname, &update_user.gender, @@ -120,8 +123,8 @@ async fn update(Json(update_user): Json) -> impl IntoResponse { } } -async fn delete_(Path(id): Path) -> impl IntoResponse { - match User::delete(&id).await { +async fn delete_(Path(user_id): Path) -> impl IntoResponse { + match User::delete(&user_id).await { Ok(user) => (StatusCode::NO_CONTENT, Json(serde_json::json!(user))), Err(err_val) => ( StatusCode::BAD_REQUEST,