Add user agent blocklist, use X-Real-IP header for IP detection

This commit is contained in:
2025-11-10 16:06:30 +03:00
Unverified
parent 320442c5fc
commit 0f86e9541c
11 changed files with 499 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
from __future__ import annotations
from typing import Callable
from fastapi import Request
from slowapi import Limiter
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from utils import get_client_ip
# Initialize limiter with IP-based key function
limiter = Limiter(
key_func=lambda request: get_client_ip(request) or get_remote_address(request),
default_limits=["1000/hour"], # Global default limit
storage_uri="memory://", # In-memory storage (can be changed to Redis later)
)
def get_user_id_key(request: Request) -> str:
"""Get rate limit key based on authenticated user ID."""
user = getattr(getattr(request, "state", None), "current_user", None)
if user and hasattr(user, "id"):
return f"user:{user.id}"
# Fallback to IP if not authenticated
return get_client_ip(request) or get_remote_address(request)
def get_ip_key(request: Request) -> str:
"""Get rate limit key based on IP address."""
return get_client_ip(request) or get_remote_address(request)
# Rate limit decorators for different endpoint types
def rate_limit_per_ip(limit: str) -> Callable:
"""Rate limit based on IP address."""
return limiter.limit(limit, key_func=get_ip_key)
def rate_limit_per_user(limit: str) -> Callable:
"""Rate limit based on authenticated user ID, fallback to IP.
Note: The user must be authenticated (get_current_user dependency must run first).
The user will be available in request.state.current_user after authentication.
"""
return limiter.limit(limit, key_func=get_user_id_key)