diff --git a/requirements b/requirements index 82fa124..1907a54 100644 --- a/requirements +++ b/requirements @@ -7,4 +7,5 @@ passlib == 1.7.4 bcrypt == 4.0.1 python-jose[cryptography] == 3.5.0 alembic == 1.16.5 -pytest == 8.4.1 \ No newline at end of file +pytest == 8.4.1 +slowapi == 0.1.9 \ No newline at end of file diff --git a/server/backend/endpoints.py b/server/backend/endpoints.py index 78eb653..5a3d2ce 100644 --- a/server/backend/endpoints.py +++ b/server/backend/endpoints.py @@ -3,6 +3,10 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from fastapi.security import OAuth2PasswordRequestForm +from .rate_limit import limiter, ratelimit_handler +from slowapi.errors import RateLimitExceeded +from slowapi.middleware import SlowAPIMiddleware + from pydantic import EmailStr from . import pydentic, JWT, password, permissions @@ -12,6 +16,9 @@ from datetime import datetime, timedelta import asyncio api = FastAPI() +api.state.limiter = limiter +api.add_exception_handler(RateLimitExceeded, ratelimit_handler) +api.add_middleware(SlowAPIMiddleware) from dotenv import load_dotenv #Работа с env для CORS import os load_dotenv() diff --git a/server/backend/rate_limit.py b/server/backend/rate_limit.py new file mode 100644 index 0000000..99589f2 --- /dev/null +++ b/server/backend/rate_limit.py @@ -0,0 +1,15 @@ +from slowapi import Limiter +from slowapi.util import get_remote_address +from slowapi.errors import RateLimitExceeded +from fastapi.responses import JSONResponse +from fastapi import Request + +# создаём limiter с глобальным лимитом +limiter = Limiter(key_func=get_remote_address, default_limits=["10/minute"]) + +# обработчик ошибок +async def ratelimit_handler(request: Request, exc: RateLimitExceeded): + return JSONResponse( + status_code=429, + content={"detail": "Too many requests, try again later."}, + ) \ No newline at end of file