feat(server): add Redis-based rate limiting middleware
Store Redis client in AppState instead of discarding it. Create rate_limit middleware using Redis INCR + EXPIRE for fixed-window counting. Apply user-based rate limiting (100 req/min) to all protected routes. Graceful degradation when Redis is unavailable.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
mod config;
|
||||
mod db;
|
||||
mod handlers;
|
||||
mod middleware;
|
||||
mod state;
|
||||
|
||||
/// OpenAPI 规范定义(预留,未来可通过 utoipa derive 合并各模块 schema)。
|
||||
@@ -16,7 +17,7 @@ mod state;
|
||||
struct ApiDoc;
|
||||
|
||||
use axum::Router;
|
||||
use axum::middleware;
|
||||
use axum::middleware as axum_middleware;
|
||||
use config::AppConfig;
|
||||
use erp_auth::middleware::jwt_auth_middleware_fn;
|
||||
use state::AppState;
|
||||
@@ -104,7 +105,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
// Connect to Redis
|
||||
let _redis_client = redis::Client::open(&config.redis.url[..])?;
|
||||
let redis_client = redis::Client::open(&config.redis.url[..])?;
|
||||
tracing::info!("Redis client created");
|
||||
|
||||
// Initialize event bus (capacity 1024 events)
|
||||
@@ -153,6 +154,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
config,
|
||||
event_bus,
|
||||
module_registry: registry,
|
||||
redis: redis_client.clone(),
|
||||
};
|
||||
|
||||
// --- Build the router ---
|
||||
@@ -172,11 +174,16 @@ async fn main() -> anyhow::Result<()> {
|
||||
.with_state(state.clone());
|
||||
|
||||
// Protected routes (JWT authentication required)
|
||||
// User-based rate limiting (100 req/min) applied after JWT auth
|
||||
let protected_routes = erp_auth::AuthModule::protected_routes()
|
||||
.merge(erp_config::ConfigModule::protected_routes())
|
||||
.merge(erp_workflow::WorkflowModule::protected_routes())
|
||||
.merge(erp_message::MessageModule::protected_routes())
|
||||
.layer(middleware::from_fn(move |req, next| {
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
middleware::rate_limit::rate_limit_by_user,
|
||||
))
|
||||
.layer(axum_middleware::from_fn(move |req, next| {
|
||||
let secret = jwt_secret.clone();
|
||||
async move { jwt_auth_middleware_fn(secret, req, next).await }
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user