feat(auth): 限制同时在线 IP 数 (默认 30, 第 31 拒绝)
背景: 防 token 泄漏被滥用 + 限共享账号人数。
- 新增 app/services/active_ip.py:
Redis ZSET 'active_ips' 存 IP,score=last_seen_unix
登录/refresh 时 check_or_register_login_ip():
IP 已在 set → 刷新 score,放行(老用户重连)
IP 不在 set + ZCARD < 30 → 加入,放行
IP 不在 set + ZCARD >= 30 → raise 429
每个已认证请求 _resolve_user() 调 touch_ip_dependency()
滑动 TTL,30 天没活动自动从 set 剔除
- get_client_ip() 取真实 IP,优先级 X-Forwarded-For > X-Real-IP > client.host
trust_x_forwarded_for 默认 True(生产 Caddy/Nginx 后面)
- config 加 3 个开关:
site_max_active_ips: int = 30
site_active_ip_idle_days: int = 30
trust_x_forwarded_for: bool = True
- admin.py 加 3 个端点:
GET /admin/active-ips — 看当前活跃 IP 列表 + last_seen
POST /admin/active-ips/kick — 强制踢出指定 IP(body={ip})
DELETE /admin/active-ips/{ip}— 简写踢出
- 注: refresh 也算 IP 占用(拿到 access token 就能用)
但已存在的 IP 直接放行,不会踢自己
This commit is contained in:
@@ -120,6 +120,15 @@ class Settings(BaseSettings):
|
||||
fetch_fail_pause_threshold: int = 3
|
||||
fetch_max_retries: int = 2
|
||||
|
||||
# ===== 站点并发登录 IP 限制 =====
|
||||
# 限制同时在线的客户端 IP 数(防滥用 + 防 token 泄漏被滥用)
|
||||
# Redis ZSET 滑动窗口:每次已认证请求刷新 score,30 天没活动自动剔除
|
||||
# 第 (limit+1) 个新 IP 登录时直接 429
|
||||
site_max_active_ips: int = 30
|
||||
site_active_ip_idle_days: int = 30
|
||||
# 是否信任反向代理的 X-Forwarded-For 头(生产用 Caddy/Nginx 必开;直连调测关)
|
||||
trust_x_forwarded_for: bool = True
|
||||
|
||||
# ===== Caddy / 域名 =====
|
||||
domain: str = ""
|
||||
acme_email: str = ""
|
||||
|
||||
Reference in New Issue
Block a user