From 5d6be08f32705ff7ca0820169726bd8bc3ce3bdb Mon Sep 17 00:00:00 2001 From: milky0217 Date: Tue, 2 Jun 2026 11:46:26 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D2=E4=B8=AA=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=AE=89=E5=85=A8=E6=BC=8F=E6=B4=9E-=E6=9C=AA?= =?UTF-8?q?=E7=BB=8F=E8=AE=A4=E8=AF=81=E7=9A=84payment=5Fsuccess=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4+=E6=9C=AA=E7=A6=81=E7=94=A8mock=5Fconfirm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handlers/payment.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/handlers/payment.rs b/src/handlers/payment.rs index a55a3d4..c710b78 100644 --- a/src/handlers/payment.rs +++ b/src/handlers/payment.rs @@ -910,16 +910,13 @@ fn format_error_html(msg: &str, order_no: &str) -> String { #[get("/payment/success")] pub async fn payment_success( - pool: web::Data, + _pool: web::Data, query: web::Query, ) -> HttpResponse { let order_no = query.order_no.as_deref().unwrap_or(""); - // 同步确认订单(幂等:已确认的订单会跳过) - if !order_no.is_empty() - && let Err(e) = db::confirm_payment_order_by_orderno(pool.get_ref(), order_no).await { - tracing::warn!("支付成功页同步确认失败(可能是异步回调已处理): {}", e); - } + // 不再在此处确认订单(安全原因: 此端点无认证, 任何人知道 order_no 即可激活会员)。 + // Mock 支付由 mock_confirm 在跳转前确认, 真实支付宝由 notify 异步回调确认。 let html = build_success_html(order_no); HttpResponse::Ok() @@ -1028,6 +1025,7 @@ pub async fn create_order( } /// POST /api/payment/mock-confirm +/// 仅在未配置支付宝时可用(否则用户可绕过真实支付) #[post("/api/payment/mock-confirm")] pub async fn mock_confirm( pool: web::Data, @@ -1035,8 +1033,13 @@ pub async fn mock_confirm( body: web::Json, ) -> Result { check_payment_maintenance()?; - let user_id = claims.user_id; + // 安全守卫:已配置支付宝时禁用 Mock 支付,防止绕过 + if AlipayConfig::from_env().is_some() { + return Err(AppError::BadRequest("真实支付已启用,Mock 支付不可用".to_string())); + } + + let user_id = claims.user_id; let expires_at = db::confirm_payment_order(pool.get_ref(), &body.order_id, user_id).await?;