fix:修复提示词工坊公开接口验证逻辑 2

This commit is contained in:
xiamuceer-j
2026-01-27 14:31:09 +08:00
parent ef0f4acce2
commit c0cb007553
2 changed files with 90 additions and 63 deletions
+35 -37
View File
@@ -39,40 +39,38 @@ def get_user_identifier(user_id: str) -> str:
def get_user_identifier_from_request(request: Request) -> str:
"""
从请求中获取用户标识
- 服务端模式:优先从 Header 获取(来自其他实例的代理请求)
- 客户端模式:从本地用户获取
中间件已经处理了代理请求,将用户标识存储在 request.state.user_id
- 代理请求:user_id 格式为 "instance_id:user_id"
- 本地请求:user_id 是本地用户ID,需要转换为 "instance_id:user_id" 格式
"""
if is_workshop_server():
# 服务端模式:检查是否来自其他实例的代理请求
instance_id = request.headers.get("X-Instance-ID")
header_user_id = request.headers.get("X-User-ID")
if instance_id and header_user_id:
# 来自其他实例的请求,使用 Header 中的用户标识
return header_user_id
# 本地用户
user_id = getattr(request.state, 'user_id', None)
if not user_id:
raise HTTPException(status_code=401, detail="未登录或用户ID缺失")
return get_user_identifier(user_id)
# 检查是否为代理请求(user_id 已经是完整格式)
is_proxy = getattr(request.state, 'is_proxy_request', False)
if is_proxy:
# 代理请求,user_id 已经是 "instance_id:user_id" 格式
return user_id
else:
# 本地请求,需要添加实例前缀
return get_user_identifier(user_id)
def get_optional_user_identifier(request: Request) -> Optional[str]:
"""
获取可选的用户标识(用于公开API,可以没有用户)
"""
if is_workshop_server():
# 服务端模式:检查是否来自其他实例的代理请求
instance_id = request.headers.get("X-Instance-ID")
header_user_id = request.headers.get("X-User-ID")
if instance_id and header_user_id:
return header_user_id
# 本地用户
user_id = getattr(request.state, 'user_id', None)
if user_id:
if not user_id:
return None
# 检查是否为代理请求
is_proxy = getattr(request.state, 'is_proxy_request', False)
if is_proxy:
return user_id
else:
return get_user_identifier(user_id)
return None
def _item_to_dict(item: PromptWorkshopItem, is_liked: bool = False) -> dict:
@@ -434,34 +432,34 @@ async def submit_prompt(
# 获取用户显示名称
submitter_name = "未知用户"
if is_workshop_server():
# 服务端模式:检查是否来自代理请求
instance_id = request.headers.get("X-Instance-ID")
if instance_id:
# 代理请求,从请求数据中获取提交者名称
submitter_name = data.author_display_name or "未知用户"
is_proxy = getattr(request.state, 'is_proxy_request', False)
if is_proxy:
# 代理请求,从请求数据中获取提交者名称
submitter_name = data.author_display_name or "未知用户"
else:
# 本地请求,从用户对象获取
user = getattr(request.state, 'user', None)
if user:
submitter_name = user.display_name
else:
# 本地请求
# 尝试从数据库获取
user_id = getattr(request.state, 'user_id', None)
if user_id:
from app.user_manager import user_manager
user = await user_manager.get_user(user_id)
submitter_name = user.display_name if user else "未知用户"
else:
# 客户端模式:本地用户
user_id = getattr(request.state, 'user_id', None)
if user_id:
from app.user_manager import user_manager
user = await user_manager.get_user(user_id)
submitter_name = user.display_name if user else "未知用户"
if is_workshop_server():
# 直接创建提交记录
# 对于代理请求,source_instance 从 Header 获取
source_instance = request.headers.get("X-Instance-ID") or INSTANCE_ID
submission = PromptSubmission(
id=str(uuid.uuid4()),
submitter_id=user_identifier,
submitter_name=submitter_name,
source_instance=INSTANCE_ID,
source_instance=source_instance,
name=data.name,
description=data.description,
prompt_content=data.prompt_content,
+55 -26
View File
@@ -1,7 +1,8 @@
"""
认证中间件 - 从 Cookie 中提取用户信息并注入到 request.state
支持来自其他实例的代理请求(提示词工坊功能)
"""
from fastapi import Request, HTTPException
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from app.user_manager import user_manager
from app.logger import get_logger
@@ -14,37 +15,65 @@ class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
"""
处理请求,从 Cookie 中提取用户 ID 并注入到 request.state
"""
# 从 Cookie 中获取用户 ID
user_id = request.cookies.get("user_id")
处理请求,从 Cookie 或 Header 中提取用户 ID 并注入到 request.state
# 注入到 request.state
if user_id:
user = await user_manager.get_user(user_id)
if user:
# 检查用户是否被禁用 (trust_level = -1)
if user.trust_level == -1:
logger.warning(f"禁用用户尝试访问: {user_id} ({user.username})")
# 清除用户状态,视为未登录
request.state.user_id = None
request.state.user = None
request.state.is_admin = False
else:
# 用户正常,注入状态
request.state.user_id = user_id
request.state.user = user
request.state.is_admin = user.is_admin
对于提示词工坊相关的代理请求(带有 X-Instance-ID Header),
从 Header 中读取用户标识而不是 Cookie。
"""
# 检查是否为来自其他实例的代理请求(提示词工坊)
instance_id = request.headers.get("X-Instance-ID")
is_workshop_path = request.url.path.startswith("/api/prompt-workshop")
if instance_id and is_workshop_path:
# 来自其他实例的代理请求
header_user_id = request.headers.get("X-User-ID")
request.state.is_proxy_request = True
request.state.proxy_instance_id = instance_id
if header_user_id:
# 有用户标识,使用代理的用户信息
request.state.user_id = header_user_id # 这是 "instance:user_id" 格式
request.state.user = None # 代理请求没有实际的 User 对象
request.state.is_admin = False
else:
# 用户不存在,清除状态
# 没有用户标识,匿名访问
request.state.user_id = None
request.state.user = None
request.state.is_admin = False
else:
# 未登录
request.state.user_id = None
request.state.user = None
request.state.is_admin = False
# 本地请求或非工坊路径,使用 Cookie 认证
request.state.is_proxy_request = False
request.state.proxy_instance_id = None
# 从 Cookie 中获取用户 ID
user_id = request.cookies.get("user_id")
if user_id:
user = await user_manager.get_user(user_id)
if user:
# 检查用户是否被禁用 (trust_level = -1)
if user.trust_level == -1:
logger.warning(f"禁用用户尝试访问: {user_id} ({user.username})")
# 清除用户状态,视为未登录
request.state.user_id = None
request.state.user = None
request.state.is_admin = False
else:
# 用户正常,注入状态
request.state.user_id = user_id
request.state.user = user
request.state.is_admin = user.is_admin
else:
# 用户不存在,清除状态
request.state.user_id = None
request.state.user = None
request.state.is_admin = False
else:
# 未登录
request.state.user_id = None
request.state.user = None
request.state.is_admin = False
# 继续处理请求
response = await call_next(request)