use crate::auth::token::create_jwt; use crate::core::AppState; use crate::domain::dto::auth::{LoginRequest, LoginResponse, MeResponse}; use crate::http::context::CurrentUser; use crate::http::error::HTTPError; use crate::routes::user::mapper::user_model_to_user_response; use axum::Json; use axum::extract::State; use axum_extra::extract::CookieJar; use axum_extra::extract::cookie::{Cookie, SameSite}; use sea_orm::ActiveModelBehavior; #[utoipa::path( post, path = "/auth/bearer-login", request_body = LoginRequest, responses( (status = 200, description = "Login successful", body = LoginResponse), (status = 401, description = "Unauthorized") ), tag = "Auth" )] pub async fn login_bearer( State(state): State, Json(payload): Json, ) -> Result, HTTPError> { let user = state .repositories .user .check_password(&payload.username, &payload.password) .await .map_err(|_| HTTPError::Unauthorized)?; let token = create_jwt( user.id, &user.username, user.is_superuser, &state.config.jwt.secret, state.config.jwt.duration, ) .map_err(|_| HTTPError::InternalServerError("Failed to create JWT token".to_string()))?; Ok(Json(LoginResponse { token })) } #[utoipa::path( post, path = "/auth/login", request_body = LoginRequest, responses( (status = 200, description = "Login successful with cookie set", body = LoginResponse), (status = 401, description = "Unauthorized") ), tag = "Auth" )] pub async fn login_cookie( State(state): State, jar: CookieJar, Json(payload): Json, ) -> Result<(CookieJar, Json), HTTPError> { let user = state .repositories .user .check_password(&payload.username, &payload.password) .await .map_err(|_| HTTPError::Unauthorized)?; let token = create_jwt( user.id, &user.username, user.is_superuser, &state.config.jwt.secret, state.config.jwt.duration, ) .map_err(|_| HTTPError::InternalServerError("Failed to create JWT token".to_string()))?; // Création du cookie sécurisé contenant le token JWT let cookie = Cookie::build(("token", token.clone())) .path("/") .http_only(true) .same_site(SameSite::Lax) .secure(false) // Mettez à true si vous forcez le HTTPS en production .build(); let updated_jar = jar.add(cookie); Ok((updated_jar, Json(LoginResponse { token }))) } #[utoipa::path( post, path = "/auth/logout", responses( (status = 200, description = "Logout successful") ), tag = "Auth" )] pub async fn logout_cookie(jar: CookieJar) -> Result { // On crée un cookie expiré en lui donnant une durée négative de 1 seconde (ou Duration::ZERO) let cookie = Cookie::build(("token", "")) .path("/") .max_age(time::Duration::seconds(-1)) .build(); let updated_jar = jar.add(cookie); Ok(updated_jar) } #[utoipa::path( post, path = "/auth/me", responses( (status = 200, description = "Token valid", body = LoginResponse), (status = 401, description = "Unauthorized") ), security( ("bearerAuth" = []) ), tag = "Auth" )] pub async fn me( State(_state): State, CurrentUser(user): CurrentUser, ) -> Result, HTTPError> { let user_response = user_model_to_user_response(user); Ok(Json(MeResponse { user: user_response, })) }