feat: add middleware

This commit is contained in:
Maulana Sodiqin
2025-03-15 01:53:20 +07:00
parent 7ab036f5f7
commit b096f4129a
6 changed files with 77 additions and 25 deletions
+65
View File
@@ -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<AppState>,
mut req: Request,
next: Next,
) -> Result<Response, Infallible> {
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<AuthQueryByEmailResponse> = 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)
}
+3 -10
View File
@@ -7,7 +7,7 @@ use super::{
use crate::{ use crate::{
common_response, encode_access_token, encode_refresh_token, hash_password, common_response, encode_access_token, encode_refresh_token, hash_password,
success_response, v1::UsersItemDto, verify_password, AppState, success_response, v1::UsersItemDto, verify_password, AppState,
ResponseSuccessDto, TokenSub, ResponseSuccessDto,
}; };
pub struct AuthService; pub struct AuthService;
@@ -31,15 +31,8 @@ impl AuthService {
); );
} }
let access_token = encode_access_token(TokenSub { let access_token = encode_access_token(payload.email.clone());
email: payload.email.clone(), let refresh_token = encode_refresh_token(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 response = ResponseSuccessDto { let response = ResponseSuccessDto {
data: AuthLoginResponsetDto { data: AuthLoginResponsetDto {
+5 -4
View File
@@ -1,5 +1,4 @@
use axum::Router; use axum::{middleware::from_fn, Router};
pub mod auth; pub mod auth;
pub mod docs; pub mod docs;
pub mod gacha; pub mod gacha;
@@ -11,7 +10,9 @@ pub use gacha::*;
pub use users::*; pub use users::*;
pub async fn routes() -> Router { pub async fn routes() -> Router {
Router::new() let public_routes = Router::new().nest("/auth", auth_router());
.nest("/auth", auth_router()) let protected_routes = Router::new()
.nest("/gacha", gacha_router()) .nest("/gacha", gacha_router())
.layer(from_fn(auth::auth_middleware::auth_middleware));
Router::new().merge(public_routes).merge(protected_routes)
} }
-1
View File
@@ -3,7 +3,6 @@ use utoipa::ToSchema;
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct UsersSchema { pub struct UsersSchema {
pub id: String,
pub email: String, pub email: String,
pub fullname: String, pub fullname: String,
pub password: String, pub password: String,
+3 -9
View File
@@ -6,20 +6,14 @@ use jsonwebtoken::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenSub {
pub email: String,
pub role_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Claims { pub struct Claims {
pub exp: usize, pub exp: usize,
pub iat: usize, pub iat: usize,
pub sub: TokenSub, pub sub: String,
} }
pub fn encode_access_token(sub: TokenSub) -> Result<String, StatusCode> { pub fn encode_access_token(sub: String) -> Result<String, StatusCode> {
let env = Env::new(); let env = Env::new();
let secret: String = env.access_token_secret; let secret: String = env.access_token_secret;
let now = Utc::now(); let now = Utc::now();
@@ -49,7 +43,7 @@ pub fn decode_access_token(
result result
} }
pub fn encode_refresh_token(sub: TokenSub) -> Result<String, StatusCode> { pub fn encode_refresh_token(sub: String) -> Result<String, StatusCode> {
let env = Env::new(); let env = Env::new();
let secret: String = env.refresh_token_secret; let secret: String = env.refresh_token_secret;
let now = Utc::now(); let now = Utc::now();