From b096f4129a0214ccd1aeeb3880c7dee7132fdcd2 Mon Sep 17 00:00:00 2001 From: Maulana Sodiqin Date: Sat, 15 Mar 2025 01:53:20 +0700 Subject: [PATCH] feat: add middleware --- src/apps/v1/auth/auth_middleware.rs | 65 +++++++++++++++++++++++++++++ src/apps/v1/auth/auth_service.rs | 13 ++---- src/apps/v1/docs/docs_controller.rs | 2 +- src/apps/v1/mod.rs | 9 ++-- src/apps/v1/users/users_schema.rs | 1 - src/libs/jsonwebtoken/mod.rs | 12 ++---- 6 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/apps/v1/auth/auth_middleware.rs b/src/apps/v1/auth/auth_middleware.rs index e69de29..c690fe9 100644 --- a/src/apps/v1/auth/auth_middleware.rs +++ b/src/apps/v1/auth/auth_middleware.rs @@ -0,0 +1,65 @@ +use crate::{common_response, decode_access_token, AppState}; +use axum::{ + extract::Request, + http::{header::AUTHORIZATION, StatusCode}, + middleware::Next, + response::Response, + Extension, +}; +use std::convert::Infallible; + +use super::{AuthQueryByEmailResponse, AuthRepository}; + +pub async fn auth_middleware( + Extension(state): Extension, + mut req: Request, + next: Next, +) -> Result { + let auth_header = match req.headers().get(AUTHORIZATION) { + Some(h) => h.to_str().unwrap_or_default(), + None => { + return Ok(common_response( + StatusCode::UNAUTHORIZED, + "You are not authorized", + )); + } + }; + + let token = auth_header.strip_prefix("Bearer ").unwrap_or(""); + + let token_data = match decode_access_token(token) { + Ok(data) => data, + Err(err) => { + return Ok(common_response( + StatusCode::UNAUTHORIZED, + &format!("Invalid or expired token: {}", &err.to_string()), + )); + } + }; + + let repository = AuthRepository::new(&state); + + let user: Option = match repository + .query_user_by_email(token_data.claims.sub.clone()) + .await + { + Ok(user) => Some(user), + Err(err) => { + return Ok(common_response( + StatusCode::INTERNAL_SERVER_ERROR, + &format!("DB error: {}", err), + )) + } + }; + + if user.is_none() { + return Ok(common_response( + StatusCode::UNAUTHORIZED, + "Unauthorized user", + )); + } + + req.extensions_mut().insert(user.unwrap()); + + Ok(next.run(req).await) +} diff --git a/src/apps/v1/auth/auth_service.rs b/src/apps/v1/auth/auth_service.rs index 57ce684..099e2eb 100644 --- a/src/apps/v1/auth/auth_service.rs +++ b/src/apps/v1/auth/auth_service.rs @@ -7,7 +7,7 @@ use super::{ use crate::{ common_response, encode_access_token, encode_refresh_token, hash_password, success_response, v1::UsersItemDto, verify_password, AppState, - ResponseSuccessDto, TokenSub, + ResponseSuccessDto, }; pub struct AuthService; @@ -31,15 +31,8 @@ impl AuthService { ); } - let access_token = encode_access_token(TokenSub { - email: payload.email.clone(), - role_name: "Admin".to_string(), - }); - - let refresh_token = encode_refresh_token(TokenSub { - email: payload.email.clone(), - role_name: "Admin".to_string(), - }); + let access_token = encode_access_token(payload.email.clone()); + let refresh_token = encode_refresh_token(payload.email.clone()); let response = ResponseSuccessDto { data: AuthLoginResponsetDto { diff --git a/src/apps/v1/docs/docs_controller.rs b/src/apps/v1/docs/docs_controller.rs index b93bd37..2427410 100644 --- a/src/apps/v1/docs/docs_controller.rs +++ b/src/apps/v1/docs/docs_controller.rs @@ -19,7 +19,7 @@ use utoipa::{ MetaRequestDto, MetaResponseDto, MessageResponseDto, - + AuthLoginRequestDto, AuthLoginResponsetDto, ResponseSuccessDto, diff --git a/src/apps/v1/mod.rs b/src/apps/v1/mod.rs index b8365df..b6dafb4 100644 --- a/src/apps/v1/mod.rs +++ b/src/apps/v1/mod.rs @@ -1,5 +1,4 @@ -use axum::Router; - +use axum::{middleware::from_fn, Router}; pub mod auth; pub mod docs; pub mod gacha; @@ -11,7 +10,9 @@ pub use gacha::*; pub use users::*; pub async fn routes() -> Router { - Router::new() - .nest("/auth", auth_router()) + let public_routes = Router::new().nest("/auth", auth_router()); + let protected_routes = Router::new() .nest("/gacha", gacha_router()) + .layer(from_fn(auth::auth_middleware::auth_middleware)); + Router::new().merge(public_routes).merge(protected_routes) } diff --git a/src/apps/v1/users/users_schema.rs b/src/apps/v1/users/users_schema.rs index 74ba992..6d0907e 100644 --- a/src/apps/v1/users/users_schema.rs +++ b/src/apps/v1/users/users_schema.rs @@ -3,7 +3,6 @@ use utoipa::ToSchema; #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersSchema { - pub id: String, pub email: String, pub fullname: String, pub password: String, diff --git a/src/libs/jsonwebtoken/mod.rs b/src/libs/jsonwebtoken/mod.rs index ac37c2a..22da1e9 100644 --- a/src/libs/jsonwebtoken/mod.rs +++ b/src/libs/jsonwebtoken/mod.rs @@ -6,20 +6,14 @@ use jsonwebtoken::{ }; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenSub { - pub email: String, - pub role_name: String, -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Claims { pub exp: usize, pub iat: usize, - pub sub: TokenSub, + pub sub: String, } -pub fn encode_access_token(sub: TokenSub) -> Result { +pub fn encode_access_token(sub: String) -> Result { let env = Env::new(); let secret: String = env.access_token_secret; let now = Utc::now(); @@ -49,7 +43,7 @@ pub fn decode_access_token( result } -pub fn encode_refresh_token(sub: TokenSub) -> Result { +pub fn encode_refresh_token(sub: String) -> Result { let env = Env::new(); let secret: String = env.refresh_token_secret; let now = Utc::now();