feat(plugin_system): 引入插件HTTP端点系统

引入了全新的 `BaseRouterComponent` 组件类型,允许插件开发者通过继承并实现 `register_endpoints` 方法来创建 FastAPI 路由。

- 插件系统现在可以自动发现并注册这些路由组件,并将它们挂载到主 FastAPI 应用的 `/plugins/<plugin_name>` 前缀下。
- 新增了全局配置 `[plugin_http_system]`,提供了总开关、API 速率限制和 API 密钥认证 (`X-API-Key`) 等功能,以确保端点的安全性和稳定性。
- 更新了 `hello_world_plugin` 插件,增加了一个简单的 `/greet` 端点作为实现示例。
This commit is contained in:
minecraft1024a
2025-11-16 12:41:35 +08:00
committed by Windpicker-owo
parent fea007b429
commit 717d4ba555
15 changed files with 257 additions and 18 deletions

32
src/common/security.py Normal file
View File

@@ -0,0 +1,32 @@
from fastapi import Depends, HTTPException, Security
from fastapi.security.api_key import APIKeyHeader
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
from src.common.logger import get_logger
from src.config.config import global_config as bot_config
logger = get_logger("security")
API_KEY_HEADER = "X-API-Key"
api_key_header_auth = APIKeyHeader(name=API_KEY_HEADER, auto_error=True)
async def get_api_key(api_key: str = Security(api_key_header_auth)) -> str:
"""
FastAPI 依赖项用于验证API密钥。
从请求头中提取 X-API-Key 并验证它是否存在于配置的有效密钥列表中。
"""
valid_keys = bot_config.plugin_http_system.plugin_api_valid_keys
if not valid_keys:
logger.warning("API密钥认证已启用但未配置任何有效的API密钥。所有请求都将被拒绝。")
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="服务未正确配置API密钥",
)
if api_key not in valid_keys:
logger.warning(f"无效的API密钥: {api_key}")
raise HTTPException(
status_code=HTTP_403_FORBIDDEN,
detail="无效的API密钥",
)
return api_key

View File

@@ -1,32 +1,60 @@
import os
import socket
from fastapi import APIRouter, FastAPI
from fastapi import APIRouter, FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from rich.traceback import install
from uvicorn import Config
from uvicorn import Server as UvicornServer
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware
from slowapi.util import get_remote_address
from src.common.logger import get_logger
from src.config.config import global_config as bot_config
install(extra_lines=3)
logger = get_logger("Server")
def rate_limit_exceeded_handler(request: Request, exc: Exception) -> Response:
"""自定义速率限制超出处理器以解决类型提示问题"""
# 由于此处理器专门用于 RateLimitExceeded我们可以安全地断言异常类型。
# 这满足了类型检查器的要求,并确保了运行时安全。
assert isinstance(exc, RateLimitExceeded)
return _rate_limit_exceeded_handler(request, exc)
class Server:
def __init__(self, host: str | None = None, port: int | None = None, app_name: str = "MaiMCore"):
def __init__(self, host: str | None = None, port: int | None = None, app_name: str = "MoFox-Bot"):
# 根据配置初始化速率限制器
limiter = Limiter(
key_func=get_remote_address,
default_limits=[bot_config.plugin_http_system.plugin_api_rate_limit_default],
)
self.app = FastAPI(title=app_name)
self.host: str = "127.0.0.1"
self.port: int = 8080
self._server: UvicornServer | None = None
self.set_address(host, port)
# 设置速率限制
self.app.state.limiter = limiter
self.app.add_exception_handler(RateLimitExceeded, rate_limit_exceeded_handler)
# 根据配置决定是否添加中间件
if bot_config.plugin_http_system.plugin_api_rate_limit_enable:
logger.info(f"已为插件API启用全局速率限制: {bot_config.plugin_http_system.plugin_api_rate_limit_default}")
self.app.add_middleware(SlowAPIMiddleware)
# 配置 CORS
origins = [
"http://localhost:3000", # 允许的前端源
"http://127.0.0.1:3000",
"http://127.0.0.1:3000",
# 在生产环境中,您应该添加实际的前端域名
]