diff --git a/app/api/endpoints/anthropic.py b/app/api/endpoints/anthropic.py index 6e1a1dc2..1ea3eade 100644 --- a/app/api/endpoints/anthropic.py +++ b/app/api/endpoints/anthropic.py @@ -39,6 +39,9 @@ def _anthropic_error_response( def _check_auth(api_key: Optional[str]) -> Optional[JSONResponse]: + """ + Anthropic 兼容接口以 API_TOKEN 认证受信客户端,认证通过即按管理员级 Agent 集成处理。 + """ if not api_key or api_key != settings.API_TOKEN: return _anthropic_error_response( "invalid x-api-key", @@ -122,6 +125,7 @@ async def messages( session_seed = anthropic_version or "anthropic" session_id = build_session_id(f"{session_seed}:{uuid.uuid4().hex}", SESSION_PREFIX) + # 兼容接口的 API_TOKEN 客户端按管理员级 MoviePilot Agent 集成处理。 agent = _CollectingMoviePilotAgent( session_id=session_id, user_id=session_id, diff --git a/app/api/endpoints/mcp.py b/app/api/endpoints/mcp.py index e23f5868..c8c7c405 100644 --- a/app/api/endpoints/mcp.py +++ b/app/api/endpoints/mcp.py @@ -19,6 +19,7 @@ router = APIRouter() # MCP 协议版本 MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18", "2024-11-05"] MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSIONS[0] # 默认使用最新版本 +# MCP 经 API_TOKEN / X-API-KEY 认证后是管理员级集成入口;隐藏工具只收敛暴露面,不构成权限边界。 MCP_HIDDEN_TOOLS = { "execute_command", "search_web", diff --git a/app/api/endpoints/openai.py b/app/api/endpoints/openai.py index 9bda42dc..607547fc 100644 --- a/app/api/endpoints/openai.py +++ b/app/api/endpoints/openai.py @@ -231,6 +231,9 @@ def _error_response( def _check_auth( credentials: Optional[HTTPAuthorizationCredentials], ) -> Optional[JSONResponse]: + """ + OpenAI 兼容接口以 API_TOKEN 认证受信客户端,认证通过即按管理员级 Agent 集成处理。 + """ if not credentials or credentials.scheme.lower() != "bearer": return _error_response( "Invalid bearer token.", @@ -317,6 +320,7 @@ async def chat_completions( session_id = build_session_id(session_key, SESSION_PREFIX) username = str(payload.user or "openai-client") + # 兼容接口的 API_TOKEN 客户端按管理员级 MoviePilot Agent 集成处理。 agent = _CollectingMoviePilotAgent( session_id=session_id, user_id=session_key, @@ -409,6 +413,7 @@ async def responses( session_key = str(payload.user or uuid.uuid4()) session_id = build_session_id(session_key, SESSION_PREFIX) + # 兼容接口的 API_TOKEN 客户端按管理员级 MoviePilot Agent 集成处理。 agent = _CollectingMoviePilotAgent( session_id=session_id, user_id=session_key, diff --git a/app/core/security.py b/app/core/security.py index 1ac1594d..1a48a179 100644 --- a/app/core/security.py +++ b/app/core/security.py @@ -316,7 +316,9 @@ def __verify_key(key: str | None, expected_key: str, key_type: str) -> str: def verify_apitoken(token: Annotated[str | None, Security(__get_api_token)]) -> str: """ - 使用 API Token 进行身份认证 + 使用 API Token 进行受信第三方集成认证。 + + 校验值来自 settings.API_TOKEN;通过后只确认集成凭据有效,不生成 per-user 权限上下文。 :param token: API Token,从 URL 查询参数中获取 token=xxx :return: 返回校验通过的 API Token """ @@ -325,7 +327,9 @@ def verify_apitoken(token: Annotated[str | None, Security(__get_api_token)]) -> def verify_apikey(apikey: Annotated[str | None, Security(__get_api_key)]) -> str: """ - 使用 API Key 进行身份认证 + 使用 API Key 形式进行受信第三方集成认证。 + + 请求字段名兼容 API Key,实际校验值来自 settings.API_TOKEN,不生成 per-user 权限上下文。 :param apikey: API Key,从 URL 查询参数中获取 apikey=xxx,或请求头中获取 X-API-KEY=xxx :return: 返回校验通过的 API Key """ diff --git a/docs/mcp-api.md b/docs/mcp-api.md index 9ce801c4..f8881dcf 100644 --- a/docs/mcp-api.md +++ b/docs/mcp-api.md @@ -11,6 +11,14 @@ MoviePilot 实现了标准的 **Model Context Protocol (MCP)**,允许 AI 智 * Header: `X-API-KEY: <你的API_KEY>` * Query: `?apikey=<你的API_KEY>` +### 安全提示 + +MCP 使用系统配置中的 `API_TOKEN` 作为认证密钥,文档中的 API KEY 是请求字段名。该密钥应按管理员级 secret 保管,持有者可作为受信第三方集成调用暴露的 MoviePilot 工具。 + +- 优先使用 `X-API-KEY` 请求头;查询参数更容易出现在代理、浏览器或客户端日志中。 +- 不要在缺少 HTTPS、访问控制和网络隔离的情况下,将 MCP、OpenAI 或 Anthropic 兼容接口直接暴露到公网。 +- MCP 隐藏工具列表只用于减少默认暴露面,不是 per-user 权限系统。 + ## 2. 标准 MCP 协议 (JSON-RPC 2.0) ### 端点 diff --git a/docs/rules/11-quality-and-security.md b/docs/rules/11-quality-and-security.md index 0197030b..4097c10e 100644 --- a/docs/rules/11-quality-and-security.md +++ b/docs/rules/11-quality-and-security.md @@ -78,6 +78,8 @@ The `API_TOKEN` value in `settings` is the source of truth. It is set at initial ### Endpoint Authorization +- API-token authenticated integration endpoints are administrator-level surfaces unless a specific endpoint documents a narrower contract. +- Do not infer user-scoped authorization from a valid `API_TOKEN`; use an explicit user identity dependency when behavior must be scoped to a logged-in user. - Use the existing FastAPI dependency functions (e.g., `get_current_user`, `get_current_active_superuser`) — check `app/api/endpoints/` for usage patterns. - Do not add manual token parsing inside endpoint functions. Always use the project's dependency injection. - Superuser-only operations must explicitly require the superuser dependency.