feat: 增强 WebUI 配置,支持防爬虫和安全 Cookie 设置

This commit is contained in:
墨梓柒
2025-12-19 00:44:22 +08:00
parent d3b71a7181
commit 3231995ebd
10 changed files with 107 additions and 47 deletions

View File

@@ -124,10 +124,8 @@ SCANNER_SPECIFIC_HEADERS = {
# strict: 严格模式(更严格的检测,更低的频率限制)
# loose: 宽松模式(较宽松的检测,较高的频率限制)
# basic: 基础模式只记录恶意访问不阻止不限制请求数不跟踪IP
ANTI_CRAWLER_MODE = os.getenv("WEBUI_ANTI_CRAWLER_MODE", "basic").lower()
# IP白名单配置从环境变量读取逗号分隔
# IP白名单配置从配置文件读取逗号分隔
# 支持格式:
# - 精确IP127.0.0.1, 192.168.1.100
# - CIDR格式192.168.1.0/24, 172.17.0.0/16 (适用于Docker网络)
@@ -236,13 +234,23 @@ def _convert_wildcard_to_regex(wildcard_pattern: str) -> Optional[str]:
return regex
ALLOWED_IPS = _parse_allowed_ips(os.getenv("WEBUI_ALLOWED_IPS", ""))
# 从配置读取防爬虫设置(延迟导入避免循环依赖)
def _get_anti_crawler_config():
"""获取防爬虫配置"""
from src.config.config import global_config
return {
'mode': global_config.webui.anti_crawler_mode,
'allowed_ips': _parse_allowed_ips(global_config.webui.allowed_ips),
'trusted_proxies': _parse_allowed_ips(global_config.webui.trusted_proxies),
'trust_xff': global_config.webui.trust_xff
}
# 信任的代理IP配置从环境变量读取逗号分隔
# 只有在信任的代理IP下才使用X-Forwarded-For头
# 默认关闭(空),不信任任何代理
TRUSTED_PROXIES = _parse_allowed_ips(os.getenv("WEBUI_TRUSTED_PROXIES", ""))
TRUST_XFF = os.getenv("WEBUI_TRUST_XFF", "false").lower() == "true"
# 初始化配置(将在模块加载时执行
_config = _get_anti_crawler_config()
ANTI_CRAWLER_MODE = _config['mode']
ALLOWED_IPS = _config['allowed_ips']
TRUSTED_PROXIES = _config['trusted_proxies']
TRUST_XFF = _config['trust_xff']
def _get_mode_config(mode: str) -> dict:

View File

@@ -3,10 +3,10 @@ WebUI 认证模块
提供统一的认证依赖,支持 Cookie 和 Header 两种方式
"""
import os
from typing import Optional
from fastapi import HTTPException, Cookie, Header, Response, Request
from src.common.logger import get_logger
from src.config.config import global_config
from .token_manager import get_token_manager
logger = get_logger("webui.auth")
@@ -23,23 +23,18 @@ def _is_secure_environment() -> bool:
Returns:
bool: 如果应该使用 secure cookie 则返回 True
"""
# 检查环境变量
secure_cookie_env = os.environ.get("WEBUI_SECURE_COOKIE", "")
if secure_cookie_env.lower() in ("true", "1", "yes"):
logger.info(f"WEBUI_SECURE_COOKIE 设置为 {secure_cookie_env},启用 secure cookie")
# 从配置读取
if global_config.webui.secure_cookie:
logger.info("配置中启用了 secure_cookie")
return True
if secure_cookie_env.lower() in ("false", "0", "no"):
logger.info(f"WEBUI_SECURE_COOKIE 设置为 {secure_cookie_env},禁用 secure cookie")
return False
# 检查是否是生产环境
env = os.environ.get("WEBUI_MODE", "").lower()
if env in ("production", "prod"):
logger.info(f"WEBUI_MODE 设置为 {env},启用 secure cookie")
if global_config.webui.mode == "production":
logger.info("WebUI运行在生产模式启用 secure cookie")
return True
# 默认:开发环境不启用(因为通常是 HTTP
logger.debug(f"未设置特殊环境变量 (WEBUI_SECURE_COOKIE={secure_cookie_env}, WEBUI_MODE={env}),禁用 secure cookie")
logger.debug("WebUI运行在开发模式,禁用 secure cookie")
return False
@@ -111,7 +106,7 @@ def set_auth_cookie(response: Response, token: str, request: Optional[Request] =
logger.warning("=" * 80)
logger.warning("检测到 HTTP 连接但环境配置要求 HTTPS (secure cookie)")
logger.warning("已自动禁用 secure 标志以允许登录,但建议修改配置:")
logger.warning("1. 在 .env 文件中设置: WEBUI_SECURE_COOKIE=false")
logger.warning("1. 在配置文件中设置: webui.secure_cookie = false")
logger.warning("2. 如果使用反向代理,请确保正确配置 X-Forwarded-Proto 头")
logger.warning("=" * 80)
is_secure = False

View File

@@ -1,6 +1,5 @@
"""独立的 WebUI 服务器 - 运行在 0.0.0.0:8001"""
import os
import asyncio
import mimetypes
from pathlib import Path
@@ -130,9 +129,10 @@ class WebUIServer:
"""配置防爬虫中间件"""
try:
from src.webui.anti_crawler import AntiCrawlerMiddleware
from src.config.config import global_config
# 从环境变量读取防爬虫模式false/strict/loose/basic
anti_crawler_mode = os.getenv("WEBUI_ANTI_CRAWLER_MODE", "basic").lower()
# 从配置读取防爬虫模式
anti_crawler_mode = global_config.webui.anti_crawler_mode
# 注意:中间件按注册顺序反向执行,所以先注册的中间件后执行
# 我们需要在CORS之前注册这样防爬虫检查会在CORS之前执行
@@ -186,7 +186,7 @@ class WebUIServer:
error_msg = f"❌ WebUI 服务器启动失败: 端口 {self.port} 已被占用"
logger.error(error_msg)
logger.error(f"💡 请检查是否有其他程序正在使用端口 {self.port}")
logger.error("💡 可以通过环境变量 WEBUI_PORT 修改 WebUI 端口")
logger.error("💡 可以在配置文件中修改 webui.port 来更改 WebUI 端口")
logger.error(f"💡 Windows 用户可以运行: netstat -ano | findstr :{self.port}")
logger.error(f"💡 Linux/Mac 用户可以运行: lsof -i :{self.port}")
raise OSError(f"端口 {self.port} 已被占用,无法启动 WebUI 服务器")
@@ -212,7 +212,7 @@ class WebUIServer:
if "address already in use" in str(e).lower() or e.errno in (98, 10048): # 98: Linux, 10048: Windows
logger.error(f"❌ WebUI 服务器启动失败: 端口 {self.port} 已被占用")
logger.error(f"💡 请检查是否有其他程序正在使用端口 {self.port}")
logger.error("💡 可以通过环境变量 WEBUI_PORT 修改 WebUI 端口")
logger.error("💡 可以在配置文件中修改 webui.port 来更改 WebUI 端口")
else:
logger.error(f"❌ WebUI 服务器启动失败 (网络错误): {e}")
raise
@@ -257,8 +257,9 @@ def get_webui_server() -> WebUIServer:
"""获取全局 WebUI 服务器实例"""
global _webui_server
if _webui_server is None:
# 从环境变量读取配置
host = os.getenv("WEBUI_HOST", "0.0.0.0")
port = int(os.getenv("WEBUI_PORT", "8001"))
# 从配置读取
from src.config.config import global_config
host = global_config.webui.host
port = global_config.webui.port
_webui_server = WebUIServer(host=host, port=port)
return _webui_server