/
rorikstr
/
multiberry-backend
Обзор
Документация
Войти
/
rorikstr
/
multiberry-backend
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
src/auth/handlers.rs
198 строк
6 KB
Rorik Star Platinum
finish 30% lol
09 ноя 2025, 21:03
09 ноя 2025, 21:03
ea863ad
Код
Авторство
О чём код?
// src/auth/handlers.rs // Authentication HTTP handlers // User registers with bank_user_number (1-10) + password // Gets JWT for accessing Multiberry endpoints // Real credentials: bank_user_id + password use axum::{ extract::State, http::StatusCode, response::IntoResponse, Json, }; use serde::{Deserialize, Serialize}; use serde_json::json; use tracing::{info, warn, error, debug}; // ← ONLY ADD THIS use crate::{state::AppState, db}; use super::{jwt::generate_token, password::{hash_password, verify_password}}; #[derive(Debug, Deserialize)] pub struct RegisterRequest { pub bank_user_number: u8, pub password: String, } #[derive(Debug, Deserialize)] pub struct LoginRequest { pub bank_user_id: String, pub password: String, } #[derive(Debug, Serialize)] pub struct AuthResponse { pub token: String, pub bank_user_id: String, } pub async fn register_handler( State(state): State<AppState>, Json(payload): Json<RegisterRequest>, ) -> impl IntoResponse { info!("🔐 REGISTER REQUEST"); debug!(" bank_user_number: {}", payload.bank_user_number); debug!(" password length: {} chars", payload.password.len()); // Validate password length if payload.password.len() < 3 { error!("❌ Password too short"); return Err(( StatusCode::BAD_REQUEST, Json(json!({ "error": "Password must be at least 3 characters" })) )); } // Validate bank_user_number (1-10) if payload.bank_user_number < 1 || payload.bank_user_number > 10 { error!("❌ Invalid bank_user_number: {}", payload.bank_user_number); return Err(( StatusCode::BAD_REQUEST, Json(json!({ "error": "bank_user_number must be between 1 and 10" })) )); } // Hash password let password_hash = hash_password(&payload.password) .map_err(|e| { error!("❌ Password hashing failed: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({ "error": "Failed to hash password" })) ) })?; debug!("✅ Password hashed successfully"); // Build bank_user_id from environment + number let bank_user_id = format!("{}-{}", state.bank_team_id, payload.bank_user_number); info!(" Generated bank_user_id: {}", bank_user_id); // Create user in database let user = db::users::create_user(&state.db_pool, &bank_user_id, &password_hash) .await .map_err(|e| { error!("❌ Database error during user creation: {}", e); ( StatusCode::CONFLICT, Json(json!({ "error": format!("User already exists or database error: {}", e) })) ) })?; info!("✅ User created in database (ID: {})", user.id); // Generate JWT token let token = generate_token(user.id, &user.bank_user_id) .map_err(|e| { error!("❌ JWT generation failed: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({ "error": "Failed to generate token" })) ) })?; info!("✅ JWT token generated"); info!("🎉 REGISTER SUCCESSFUL for user: {}", bank_user_id); Ok::<_, (StatusCode, Json<serde_json::Value>)>(( StatusCode::CREATED, Json(AuthResponse { token, bank_user_id: user.bank_user_id, }) )) } pub async fn login_handler( State(state): State<AppState>, Json(payload): Json<LoginRequest>, ) -> impl IntoResponse { info!("🔑 LOGIN REQUEST"); debug!(" bank_user_id: {}", payload.bank_user_id); debug!(" password length: {} chars", payload.password.len()); // Look up user by bank_user_id let user_data = db::users::get_user_by_bank_user_id(&state.db_pool, &payload.bank_user_id) .await .map_err(|e| { error!("❌ Database error: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({ "error": "Database error" })) ) })? .ok_or_else(|| { warn!("⚠️ User not found: {}", payload.bank_user_id); ( StatusCode::UNAUTHORIZED, Json(json!({ "error": "Invalid bank_user_id or password" })) ) })?; let (user_id, password_hash) = user_data; info!("✅ User found in database (ID: {})", user_id); // Verify password let is_valid = verify_password(&payload.password, &password_hash) .map_err(|e| { error!("❌ Password verification error: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({ "error": "Password verification failed" })) ) })?; if !is_valid { warn!("⚠️ Invalid password for user: {}", payload.bank_user_id); return Err(( StatusCode::UNAUTHORIZED, Json(json!({ "error": "Invalid bank_user_id or password" })) )); } info!("✅ Password verified"); // Generate JWT token let token = generate_token(user_id, &payload.bank_user_id) .map_err(|e| { error!("❌ JWT generation failed: {}", e); ( StatusCode::INTERNAL_SERVER_ERROR, Json(json!({ "error": "Failed to generate token" })) ) })?; info!("✅ JWT token generated"); info!("🎉 LOGIN SUCCESSFUL for user: {}", payload.bank_user_id); Ok::<_, (StatusCode, Json<serde_json::Value>)>(( StatusCode::OK, Json(AuthResponse { token, bank_user_id: payload.bank_user_id, }) )) } pub async fn me_handler( axum::extract::Extension(claims): axum::extract::Extension<super::jwt::Claims>, ) -> impl IntoResponse { info!("👤 GET ME REQUEST from user: {}", claims.bank_user_id); ( StatusCode::OK, Json(json!({ "user_id": claims.sub, "bank_user_id": claims.bank_user_id, })) ) }