feat(backend): rate limit auth routes with tower_governor
This commit is contained in:
@@ -3,6 +3,8 @@ mod error;
|
||||
mod model;
|
||||
mod web;
|
||||
|
||||
use std::{net::SocketAddr, time::Duration};
|
||||
|
||||
use anyhow::Result;
|
||||
use axum::{
|
||||
Router,
|
||||
@@ -13,6 +15,9 @@ use axum::{
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
use tower_cookies::CookieManagerLayer;
|
||||
use tower_governor::{
|
||||
GovernorLayer, governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor,
|
||||
};
|
||||
use tower_http::{
|
||||
cors::CorsLayer,
|
||||
services::{ServeDir, ServeFile},
|
||||
@@ -44,6 +49,26 @@ async fn main() -> Result<()> {
|
||||
|
||||
dotenvy::dotenv().ok();
|
||||
|
||||
let governor_conf_auth = GovernorConfigBuilder::default()
|
||||
.per_second(4)
|
||||
.burst_size(2)
|
||||
.key_extractor(SmartIpKeyExtractor)
|
||||
.finish()
|
||||
.unwrap();
|
||||
let governor_auth_limiter = governor_conf_auth.limiter().clone();
|
||||
let interval = Duration::from_secs(60);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
std::thread::sleep(interval);
|
||||
info!(
|
||||
"rate limiting auth storage size: {}",
|
||||
governor_auth_limiter.len()
|
||||
);
|
||||
governor_auth_limiter.retain_recent();
|
||||
}
|
||||
});
|
||||
|
||||
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
let pool = PgPool::connect(&database_url).await.unwrap();
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
@@ -53,7 +78,8 @@ async fn main() -> Result<()> {
|
||||
.layer(DefaultBodyLimit::disable());
|
||||
|
||||
let user_repository = UserRepository::new(pool)?;
|
||||
let routes_auth = routes_auth(user_repository.clone());
|
||||
let routes_auth =
|
||||
routes_auth(user_repository.clone()).layer(GovernorLayer::new(governor_conf_auth));
|
||||
|
||||
let app = Router::new()
|
||||
.nest("/api", routes_file)
|
||||
@@ -80,7 +106,11 @@ async fn main() -> Result<()> {
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||
info!("listening on {}", listener.local_addr().unwrap());
|
||||
|
||||
axum::serve(listener, app).await?;
|
||||
axum::serve(
|
||||
listener,
|
||||
app.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user