mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
docs(security): clarify api token admin contract (#6048)
This commit is contained in:
@@ -39,6 +39,9 @@ def _anthropic_error_response(
|
|||||||
|
|
||||||
|
|
||||||
def _check_auth(api_key: Optional[str]) -> Optional[JSONResponse]:
|
def _check_auth(api_key: Optional[str]) -> Optional[JSONResponse]:
|
||||||
|
"""
|
||||||
|
Anthropic 兼容接口以 API_TOKEN 认证受信客户端,认证通过即按管理员级 Agent 集成处理。
|
||||||
|
"""
|
||||||
if not api_key or api_key != settings.API_TOKEN:
|
if not api_key or api_key != settings.API_TOKEN:
|
||||||
return _anthropic_error_response(
|
return _anthropic_error_response(
|
||||||
"invalid x-api-key",
|
"invalid x-api-key",
|
||||||
@@ -122,6 +125,7 @@ async def messages(
|
|||||||
|
|
||||||
session_seed = anthropic_version or "anthropic"
|
session_seed = anthropic_version or "anthropic"
|
||||||
session_id = build_session_id(f"{session_seed}:{uuid.uuid4().hex}", SESSION_PREFIX)
|
session_id = build_session_id(f"{session_seed}:{uuid.uuid4().hex}", SESSION_PREFIX)
|
||||||
|
# 兼容接口的 API_TOKEN 客户端按管理员级 MoviePilot Agent 集成处理。
|
||||||
agent = _CollectingMoviePilotAgent(
|
agent = _CollectingMoviePilotAgent(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
user_id=session_id,
|
user_id=session_id,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ router = APIRouter()
|
|||||||
# MCP 协议版本
|
# MCP 协议版本
|
||||||
MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18", "2024-11-05"]
|
MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18", "2024-11-05"]
|
||||||
MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSIONS[0] # 默认使用最新版本
|
MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSIONS[0] # 默认使用最新版本
|
||||||
|
# MCP 经 API_TOKEN / X-API-KEY 认证后是管理员级集成入口;隐藏工具只收敛暴露面,不构成权限边界。
|
||||||
MCP_HIDDEN_TOOLS = {
|
MCP_HIDDEN_TOOLS = {
|
||||||
"execute_command",
|
"execute_command",
|
||||||
"search_web",
|
"search_web",
|
||||||
|
|||||||
@@ -231,6 +231,9 @@ def _error_response(
|
|||||||
def _check_auth(
|
def _check_auth(
|
||||||
credentials: Optional[HTTPAuthorizationCredentials],
|
credentials: Optional[HTTPAuthorizationCredentials],
|
||||||
) -> Optional[JSONResponse]:
|
) -> Optional[JSONResponse]:
|
||||||
|
"""
|
||||||
|
OpenAI 兼容接口以 API_TOKEN 认证受信客户端,认证通过即按管理员级 Agent 集成处理。
|
||||||
|
"""
|
||||||
if not credentials or credentials.scheme.lower() != "bearer":
|
if not credentials or credentials.scheme.lower() != "bearer":
|
||||||
return _error_response(
|
return _error_response(
|
||||||
"Invalid bearer token.",
|
"Invalid bearer token.",
|
||||||
@@ -317,6 +320,7 @@ async def chat_completions(
|
|||||||
|
|
||||||
session_id = build_session_id(session_key, SESSION_PREFIX)
|
session_id = build_session_id(session_key, SESSION_PREFIX)
|
||||||
username = str(payload.user or "openai-client")
|
username = str(payload.user or "openai-client")
|
||||||
|
# 兼容接口的 API_TOKEN 客户端按管理员级 MoviePilot Agent 集成处理。
|
||||||
agent = _CollectingMoviePilotAgent(
|
agent = _CollectingMoviePilotAgent(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
user_id=session_key,
|
user_id=session_key,
|
||||||
@@ -409,6 +413,7 @@ async def responses(
|
|||||||
|
|
||||||
session_key = str(payload.user or uuid.uuid4())
|
session_key = str(payload.user or uuid.uuid4())
|
||||||
session_id = build_session_id(session_key, SESSION_PREFIX)
|
session_id = build_session_id(session_key, SESSION_PREFIX)
|
||||||
|
# 兼容接口的 API_TOKEN 客户端按管理员级 MoviePilot Agent 集成处理。
|
||||||
agent = _CollectingMoviePilotAgent(
|
agent = _CollectingMoviePilotAgent(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
user_id=session_key,
|
user_id=session_key,
|
||||||
|
|||||||
@@ -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:
|
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
|
:param token: API Token,从 URL 查询参数中获取 token=xxx
|
||||||
:return: 返回校验通过的 API Token
|
: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:
|
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
|
:param apikey: API Key,从 URL 查询参数中获取 apikey=xxx,或请求头中获取 X-API-KEY=xxx
|
||||||
:return: 返回校验通过的 API Key
|
:return: 返回校验通过的 API Key
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ MoviePilot 实现了标准的 **Model Context Protocol (MCP)**,允许 AI 智
|
|||||||
* Header: `X-API-KEY: <你的API_KEY>`
|
* Header: `X-API-KEY: <你的API_KEY>`
|
||||||
* Query: `?apikey=<你的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)
|
## 2. 标准 MCP 协议 (JSON-RPC 2.0)
|
||||||
|
|
||||||
### 端点
|
### 端点
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ The `API_TOKEN` value in `settings` is the source of truth. It is set at initial
|
|||||||
|
|
||||||
### Endpoint Authorization
|
### 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.
|
- 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.
|
- 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.
|
- Superuser-only operations must explicitly require the superuser dependency.
|
||||||
|
|||||||
Reference in New Issue
Block a user