perf: improve compression reliability and deployment safety

This commit is contained in:
237899745
2026-07-25 10:29:49 +08:00
parent 06220ca921
commit 9d7668bdee
34 changed files with 1391 additions and 1042 deletions

View File

@@ -1,16 +1,11 @@
use crate::auth;
use crate::api::envelope::Envelope;
use crate::auth;
use crate::error::{AppError, ErrorCode};
use crate::services::mail;
use crate::state::AppState;
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use axum::{
extract::State,
http::HeaderMap,
routing::post,
Json, Router,
};
use axum::{extract::State, http::HeaderMap, routing::post, Json, Router};
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
use chrono::{DateTime, Duration, Utc};
use rand::RngCore;
@@ -106,8 +101,12 @@ async fn register(
.await
.map_err(map_unique_violation)?;
let (token, _expires_at) =
auth::issue_jwt(&state.config.jwt_secret, state.config.jwt_expiry_hours, user.id, &user.role)?;
let (token, _expires_at) = auth::issue_jwt(
&state.config.jwt_secret,
state.config.jwt_expiry_hours,
user.id,
&user.role,
)?;
let verification_token = generate_token();
let token_hash = sha256_hex(&verification_token);
@@ -133,7 +132,9 @@ async fn register(
mail::send_verification_email(&state, &user.email, &user.username, &verification_url)
.await
.map_err(|err| AppError::new(ErrorCode::MailSendFailed, "验证邮件发送失败").with_source(err))?;
.map_err(|err| {
AppError::new(ErrorCode::MailSendFailed, "验证邮件发送失败").with_source(err)
})?;
let body = RegisterResponse {
user: UserView {
@@ -159,7 +160,10 @@ async fn login(
) -> Result<Json<Envelope<LoginResponse>>, AppError> {
let identity = req.email.trim();
if identity.is_empty() {
return Err(AppError::new(ErrorCode::InvalidRequest, "邮箱或用户名不能为空"));
return Err(AppError::new(
ErrorCode::InvalidRequest,
"邮箱或用户名不能为空",
));
}
let user = if identity.contains('@') {
@@ -210,8 +214,12 @@ async fn login(
verify_password(&req.password, &user.password_hash)?;
let (token, expires_at) =
auth::issue_jwt(&state.config.jwt_secret, state.config.jwt_expiry_hours, user.id, &user.role)?;
let (token, expires_at) = auth::issue_jwt(
&state.config.jwt_secret,
state.config.jwt_expiry_hours,
user.id,
&user.role,
)?;
Ok(Json(Envelope {
success: true,
@@ -241,7 +249,11 @@ async fn send_verification(
let claims = auth::require_jwt(&state.config.jwt_secret, &headers)?;
// Rate limit: 1 per minute per user
let key = format!("rate:send_verification:{}:{}", claims.sub, Utc::now().format("%Y%m%d%H%M"));
let key = format!(
"rate:send_verification:{}:{}",
claims.sub,
Utc::now().format("%Y%m%d%H%M")
);
let mut redis = state.redis.clone();
let count: i64 = redis::cmd("INCR")
.arg(&key)
@@ -257,7 +269,10 @@ async fn send_verification(
.unwrap_or(());
}
if count > 1 {
return Err(AppError::new(ErrorCode::RateLimited, "发送过于频繁,请稍后再试"));
return Err(AppError::new(
ErrorCode::RateLimited,
"发送过于频繁,请稍后再试",
));
}
let user = sqlx::query_as::<_, UserRow>(
@@ -313,7 +328,9 @@ async fn send_verification(
mail::send_verification_email(&state, &user.email, &user.username, &verification_url)
.await
.map_err(|err| AppError::new(ErrorCode::MailSendFailed, "验证邮件发送失败").with_source(err))?;
.map_err(|err| {
AppError::new(ErrorCode::MailSendFailed, "验证邮件发送失败").with_source(err)
})?;
Ok(Json(Envelope {
success: true,
@@ -434,7 +451,8 @@ async fn forgot_password(
state.config.public_base_url, reset_token
);
let _ = mail::send_password_reset_email(&state, &user.email, &user.username, &reset_url).await;
let _ =
mail::send_password_reset_email(&state, &user.email, &user.username, &reset_url).await;
}
Ok(Json(Envelope {
@@ -497,12 +515,14 @@ async fn reset_password(
.await
.map_err(|err| AppError::new(ErrorCode::Internal, "更新密码失败").with_source(err))?;
sqlx::query("UPDATE password_resets SET used_at = $2 WHERE token_hash = $1 AND used_at IS NULL")
.bind(token_hash)
.bind(now)
.execute(&mut *tx)
.await
.map_err(|err| AppError::new(ErrorCode::Internal, "更新重置记录失败").with_source(err))?;
sqlx::query(
"UPDATE password_resets SET used_at = $2 WHERE token_hash = $1 AND used_at IS NULL",
)
.bind(token_hash)
.bind(now)
.execute(&mut *tx)
.await
.map_err(|err| AppError::new(ErrorCode::Internal, "更新重置记录失败").with_source(err))?;
tx.commit()
.await