fix(server): Rate limit fail-close 改为环境变量控制
Some checks failed
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled

开发环境默认 fail-open(Redis 不可达时放行),
生产环境设置 ERP__RATE_LIMIT__FAIL_CLOSE=true 启用 fail-close(返回 503)。
This commit is contained in:
iven
2026-04-28 01:30:05 +08:00
parent d1d8079494
commit a66d59e86b

View File

@@ -180,13 +180,21 @@ pub async fn account_lockout_middleware(
) -> Response {
let avail = redis_avail();
// Redis 可达 fail-close:拒绝登录请求(安全优先
// Redis 可达性检查:生产环境 fail-close,开发环境 fail-open通过环境变量控制
let fail_close = std::env::var("ERP__RATE_LIMIT__FAIL_CLOSE")
.map(|v| v == "true" || v == "1")
.unwrap_or(false);
if !avail.should_try().await {
tracing::error!("Redis 不可达,fail-close 拒绝登录请求");
return (StatusCode::SERVICE_UNAVAILABLE, axum::Json(RateLimitResponse {
error: "service_unavailable".to_string(),
message: "安全服务暂不可用,请稍后重试".to_string(),
})).into_response();
if fail_close {
tracing::error!("Redis 不可达fail-close 拒绝登录请求");
return (StatusCode::SERVICE_UNAVAILABLE, axum::Json(RateLimitResponse {
error: "service_unavailable".to_string(),
message: "安全服务暂不可用,请稍后重试".to_string(),
})).into_response();
}
tracing::error!("Redis 不可达fail-open 放行(非生产模式,建议设置 ERP__RATE_LIMIT__FAIL_CLOSE=true");
return next.run(req).await;
}
// 获取 Redis 连接
@@ -196,12 +204,16 @@ pub async fn account_lockout_middleware(
c
}
Err(e) => {
tracing::error!(error = %e, "Redis 连接失败fail-close 拒绝登录请求");
avail.mark_failed().await;
return (StatusCode::SERVICE_UNAVAILABLE, axum::Json(RateLimitResponse {
error: "service_unavailable".to_string(),
message: "安全服务暂不可用,请稍后重试".to_string(),
})).into_response();
if fail_close {
tracing::error!(error = %e, "Redis 连接失败fail-close 拒绝登录请求");
return (StatusCode::SERVICE_UNAVAILABLE, axum::Json(RateLimitResponse {
error: "service_unavailable".to_string(),
message: "安全服务暂不可用,请稍后重试".to_string(),
})).into_response();
}
tracing::error!(error = %e, "Redis 连接失败fail-open 放行(非生产模式)");
return next.run(req).await;
}
};