superxuu commited on
Commit
d36190a
·
1 Parent(s): f3f02a5

feat: add rate limiting to register and login endpoints (10/sec)

Browse files
backend/app/api.py CHANGED
@@ -36,6 +36,7 @@ from .database_user import (
36
  match_pending_payment_order,
37
  register_user,
38
  )
 
39
 
40
  VMQ_GATEWAY_URL = os.getenv("VMQ_GATEWAY_URL", "")
41
 
@@ -177,7 +178,8 @@ async def health_check():
177
 
178
 
179
  @router.post("/v1/auth/register", response_model=AuthResponse)
180
- async def register(payload: RegisterRequest, db: Session = Depends(get_user_db)):
 
181
  username = payload.username.strip()
182
  if len(username) < 3 or len(payload.password) < 6:
183
  raise HTTPException(status_code=400, detail="用户名至少3位,密码至少6位")
@@ -201,7 +203,8 @@ async def register(payload: RegisterRequest, db: Session = Depends(get_user_db))
201
 
202
 
203
  @router.post("/v1/auth/login", response_model=AuthResponse)
204
- async def login(payload: LoginRequest, db: Session = Depends(get_user_db)):
 
205
  user = db.query(User).filter(User.username == payload.username.strip()).first()
206
  if not user or not verify_password(payload.password, user.password_hash):
207
  raise HTTPException(status_code=401, detail="用户名或密码错误")
 
36
  match_pending_payment_order,
37
  register_user,
38
  )
39
+ from .limiter import limiter
40
 
41
  VMQ_GATEWAY_URL = os.getenv("VMQ_GATEWAY_URL", "")
42
 
 
178
 
179
 
180
  @router.post("/v1/auth/register", response_model=AuthResponse)
181
+ @limiter.limit("10/second")
182
+ async def register(request: Request, payload: RegisterRequest, db: Session = Depends(get_user_db)):
183
  username = payload.username.strip()
184
  if len(username) < 3 or len(payload.password) < 6:
185
  raise HTTPException(status_code=400, detail="用户名至少3位,密码至少6位")
 
203
 
204
 
205
  @router.post("/v1/auth/login", response_model=AuthResponse)
206
+ @limiter.limit("10/second")
207
+ async def login(request: Request, payload: LoginRequest, db: Session = Depends(get_user_db)):
208
  user = db.query(User).filter(User.username == payload.username.strip()).first()
209
  if not user or not verify_password(payload.password, user.password_hash):
210
  raise HTTPException(status_code=401, detail="用户名或密码错误")
backend/app/limiter.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from slowapi import Limiter
2
+ from slowapi.util import get_remote_address
3
+
4
+ # 创建全局限制器
5
+ # 使用远程 IP 作为限制标识
6
+ limiter = Limiter(key_func=get_remote_address)
backend/app/main.py CHANGED
@@ -10,6 +10,10 @@ from contextlib import asynccontextmanager
10
  from fastapi import FastAPI
11
  from fastapi.staticfiles import StaticFiles
12
  from fastapi.middleware.cors import CORSMiddleware
 
 
 
 
13
 
14
  from .api import router
15
  from .database import get_db
@@ -78,6 +82,10 @@ app = FastAPI(
78
  lifespan=lifespan
79
  )
80
 
 
 
 
 
81
  # CORS 配置
82
  app.add_middleware(
83
  CORSMiddleware,
 
10
  from fastapi import FastAPI
11
  from fastapi.staticfiles import StaticFiles
12
  from fastapi.middleware.cors import CORSMiddleware
13
+ from slowapi.errors import RateLimitExceeded
14
+ from slowapi import _rate_limit_exceeded_handler
15
+
16
+ from .limiter import limiter
17
 
18
  from .api import router
19
  from .database import get_db
 
82
  lifespan=lifespan
83
  )
84
 
85
+ # 注册限制器
86
+ app.state.limiter = limiter
87
+ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
88
+
89
  # CORS 配置
90
  app.add_middleware(
91
  CORSMiddleware,
backend/requirements.txt CHANGED
@@ -10,4 +10,5 @@ yfinance>=0.2.36
10
  apscheduler>=3.10.4
11
  pytz>=2024.1
12
  sqlalchemy>=2.0.35
 
13
 
 
10
  apscheduler>=3.10.4
11
  pytz>=2024.1
12
  sqlalchemy>=2.0.35
13
+ slowapi>=0.1.9
14