feat(server): BLE 网关独立限流 — 每网关 60 req/60s
为 /health/gateway 路由添加 gateway_id 级别的速率限制, 网关认证(API Key)→ 限流检查 → handler 三层中间件。 Redis 不可达时同样遵循 fail_close 策略。
This commit is contained in:
@@ -750,6 +750,10 @@ async fn main() -> anyhow::Result<()> {
|
||||
.nest(
|
||||
"/health/gateway",
|
||||
erp_health::HealthModule::gateway_routes()
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
middleware::rate_limit::rate_limit_by_gateway,
|
||||
))
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
erp_health::gateway_auth::gateway_auth_middleware,
|
||||
|
||||
@@ -268,3 +268,34 @@ fn extract_client_ip(headers: &axum::http::HeaderMap) -> String {
|
||||
})
|
||||
.unwrap_or_else(|| "unknown".to_string())
|
||||
}
|
||||
|
||||
/// BLE 网关级别的限流中间件。
|
||||
///
|
||||
/// 从 GatewayAuthContext 中读取 gateway_id 作为标识符。
|
||||
/// 限制每个网关设备 60 req/60s。
|
||||
/// 必须在 gateway_auth_middleware 之后挂载(需要认证上下文)。
|
||||
pub async fn rate_limit_by_gateway(
|
||||
State(state): State<AppState>,
|
||||
req: Request<Body>,
|
||||
next: Next,
|
||||
) -> Response {
|
||||
let identifier = req
|
||||
.extensions()
|
||||
.get::<erp_health::gateway_auth::GatewayAuthContext>()
|
||||
.map(|ctx| ctx.gateway_id.clone())
|
||||
.unwrap_or_else(|| "unknown_gateway".to_string());
|
||||
let fail_close = state.config.rate_limit.fail_close;
|
||||
apply_rate_limit(
|
||||
RateLimitParams {
|
||||
redis_client: &state.redis,
|
||||
fail_close,
|
||||
max_requests: 60,
|
||||
window_secs: 60,
|
||||
prefix: "gateway",
|
||||
},
|
||||
&identifier,
|
||||
req,
|
||||
next,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user