diff --git a/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs b/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs index 416566950..c65cba3ac 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs @@ -501,7 +501,8 @@ fn auth_route(route: &str) -> AuthRoute { /// /// 会话路由的 `401/403` 归到权威失效变体,调用方据此清会话;登录路由的 `401` 是用户可修正的 /// 输入问题。可判定的用户输入原因只进业务变体,认不出的才落到 `UnexpectedRejection`。 -/// 网络、5xx 与契约异常必须保留会话。 +/// `429` 也按路由判定:发码路由是频控,登录路由是「验证码错误次数过多」,两者都是用户可修正的 +/// 输入问题;其余路由的 `429` 仍按未识别拒绝处理。网络、5xx 与契约异常必须保留会话。 fn map_auth_failure(status: StatusCode, body: &str, route: AuthRoute) -> ClientAuthError { crate::platform_maintenance::watch_platform_response(status.as_u16(), body); let status_code = status.as_u16(); @@ -526,8 +527,17 @@ fn map_auth_failure(status: StatusCode, body: &str, route: AuthRoute) -> ClientA }), }; } - if status == StatusCode::TOO_MANY_REQUESTS && route == AuthRoute::SendCode { - return ClientAuthError::SmsCodeThrottled; + if status == StatusCode::TOO_MANY_REQUESTS { + return match route { + AuthRoute::SendCode => ClientAuthError::SmsCodeThrottled, + AuthRoute::PhoneLogin => { + ClientAuthError::PhoneCodeLoginRejected(PhoneCodeLoginRejected { server_message }) + } + _ => ClientAuthError::UnexpectedRejection(UnexpectedRejection { + status: status_code, + server_message, + }), + }; } if status == StatusCode::BAD_REQUEST { return match route { @@ -1350,6 +1360,33 @@ mod tests { ); assert_eq!(throttled, ClientAuthError::SmsCodeThrottled); + // 登录路由的 429 是「验证码错误次数过多」:用户可修正的输入问题,不能进系统变体被上报。 + let verify_attempts_exceeded = map_auth_failure( + StatusCode::TOO_MANY_REQUESTS, + r#"{"error":{"message":"验证码错误次数过多,请重新获取验证码"}}"#, + AuthRoute::PhoneLogin, + ); + assert_eq!( + verify_attempts_exceeded, + ClientAuthError::PhoneCodeLoginRejected(PhoneCodeLoginRejected { + server_message: Some("验证码错误次数过多,请重新获取验证码".to_string()), + }) + ); + + // 其余路由的 429 仍未识别拒绝:既不冒充业务原因,也不冒充发码频控。 + let unknown_throttle = map_auth_failure( + StatusCode::TOO_MANY_REQUESTS, + r#"{"error":{"message":"限流"}}"#, + AuthRoute::Other, + ); + assert_eq!( + unknown_throttle, + ClientAuthError::UnexpectedRejection(UnexpectedRejection { + status: 429, + server_message: Some("限流".to_string()), + }) + ); + let bad_code = map_auth_failure( StatusCode::UNAUTHORIZED, r#"{"error":{"message":"验证码错误"}}"#,