use axum::{ Json, extract::{Extension, State}, http::{HeaderMap, StatusCode}, response::IntoResponse, }; use module_auth::{ChangePasswordInput, PasswordEntryError, ResetPasswordInput}; use shared_contracts::auth::{ PasswordChangeRequest, PasswordChangeResponse, PasswordResetRequest, PasswordResetResponse, }; use time::OffsetDateTime; use crate::{ api_response::json_success_body, auth::AuthenticatedAccessToken, auth_payload::map_auth_user_payload, auth_session::{ attach_set_cookie_header, build_refresh_session_cookie_header, create_auth_session, }, http_error::AppError, phone_auth::map_phone_auth_error, request_context::RequestContext, session_client::resolve_session_client_context, state::AppState, }; pub async fn change_password( State(state): State, Extension(request_context): Extension, Extension(authenticated): Extension, Json(payload): Json, ) -> Result, AppError> { let result = state .password_entry_service() .change_password(ChangePasswordInput { user_id: authenticated.claims().user_id().to_string(), current_password: payload.current_password, new_password: payload.new_password, }) .await .map_err(map_password_management_error)?; Ok(json_success_body( Some(&request_context), PasswordChangeResponse { user: map_auth_user_payload(result.user), }, )) } pub async fn reset_password( State(state): State, Extension(request_context): Extension, headers: HeaderMap, Json(payload): Json, ) -> Result { if !state.config.sms_auth_enabled { return Err( AppError::from_status(StatusCode::BAD_REQUEST).with_message("手机号登录暂未启用") ); } let result = state .phone_auth_service() .reset_password( ResetPasswordInput { phone_number: payload.phone, verify_code: payload.code, new_password: payload.new_password, }, OffsetDateTime::now_utc(), ) .await .map_err(map_phone_auth_error)?; let session_client = resolve_session_client_context(&headers); let signed_session = create_auth_session( &state, &result.user, &session_client, module_auth::AuthLoginMethod::Password, )?; let mut headers = HeaderMap::new(); attach_set_cookie_header( &mut headers, build_refresh_session_cookie_header(&state, &signed_session.refresh_token)?, ); Ok(( headers, json_success_body( Some(&request_context), PasswordResetResponse { token: signed_session.access_token, user: map_auth_user_payload(result.user), }, ), )) } fn map_password_management_error(error: PasswordEntryError) -> AppError { match error { PasswordEntryError::InvalidPhoneNumber | PasswordEntryError::InvalidPublicUserCode => { AppError::from_status(StatusCode::BAD_REQUEST).with_message(error.to_string()) } PasswordEntryError::InvalidPasswordLength => AppError::from_status(StatusCode::BAD_REQUEST) .with_message("密码长度需要在 6 到 128 位之间"), PasswordEntryError::InvalidCredentials => { AppError::from_status(StatusCode::UNAUTHORIZED).with_message("当前密码错误") } PasswordEntryError::UserNotFound => AppError::from_status(StatusCode::UNAUTHORIZED) .with_message("当前登录态已失效,请重新登录"), PasswordEntryError::Store(_) | PasswordEntryError::PasswordHash(_) => { AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(error.to_string()) } } }