Browse Source

feat: 调整app token认证

zhangwl 2 months ago
parent
commit
77883a313e
3 changed files with 52 additions and 46 deletions
  1. 2 1
      app/db/redis_client.py
  2. 24 3
      app/dependencies/auth.py
  3. 26 42
      app/routers/chat.py

+ 2 - 1
app/db/redis_client.py

@@ -55,6 +55,7 @@ def get_app_user(token: str) -> Optional[dict]:
             "nickName": body["nickName"],
             "mobile": body["mobile"],
             "imageUrl": body.get("imageUrl", ""),
+            "appName": body["appName"],
         }
 
         # 3. 写入 Redis 缓存
@@ -68,4 +69,4 @@ def get_app_user(token: str) -> Optional[dict]:
 
     except Exception as e:
         print(f"第三方接口调用失败: {e}")
-        return None
+        return None

+ 24 - 3
app/dependencies/auth.py

@@ -1,6 +1,7 @@
 from fastapi import HTTPException, Query, Depends
 from fastapi.security import OAuth2PasswordBearer
 from typing import Optional, Annotated
+from pydantic import BaseModel
 import jwt
 
 from ..db.redis_client import get_app_user
@@ -10,23 +11,43 @@ config = Config()
 oauth2_scheme_optional = OAuth2PasswordBearer(tokenUrl="/users/token", auto_error=False)
 
 
+class UserContext(BaseModel):
+    user_id: str
+    app_name: str
+
+
 async def resolve_user_id(
     jwt_token: Annotated[Optional[str], Depends(oauth2_scheme_optional)] = None,
     source: Optional[str] = Query(default=None),
     token: Optional[str] = Query(default=None),
-) -> str:
+) -> UserContext:
     if source == "app" and token:
         app_user = get_app_user(token)
         if not app_user:
             raise HTTPException(status_code=401, detail="无效的 App token")
-        return f"app_{app_user['userId']}"
+
+        user_id = app_user.get("userId")
+        app_name = app_user.get("appName")
+        if not user_id or not app_name:
+            raise HTTPException(status_code=401, detail="无效的 App token")
+
+        return UserContext(
+            user_id=user_id,
+            app_name=app_name,
+        )
+
     if not jwt_token:
         raise HTTPException(status_code=401, detail="未提供认证令牌")
+
     try:
         payload = jwt.decode(jwt_token, config.SECRET_KEY, algorithms=[config.ALGORITHM])
         user_id = payload.get("userId")
         if not user_id:
             raise HTTPException(status_code=401, detail="无效的令牌")
-        return user_id
+
+        return UserContext(
+            user_id=user_id,
+            app_name="com.yunxingshnegtai",
+        )
     except jwt.PyJWTError:
         raise HTTPException(status_code=401, detail="无效的令牌")

+ 26 - 42
app/routers/chat.py

@@ -13,22 +13,22 @@ from ..utils.chat_utils import get_latest_user_message, get_previous_response_id
 from ..routers.users import get_current_active_user, User
 from ..db.mongo import save_chat_log, save_chat_history, get_chat_history, delete_chat_history, get_sessions
 from ..db.ai_config import get_config_by_app_name
-from ..dependencies.auth import resolve_user_id
+from ..dependencies.auth import resolve_user_id, UserContext
 
 config = Config()
 
 router = APIRouter()
 
 
-async def generate_stream_response(request: ChatRequest, user_id: str, app_name: str = "com.yunxiangshengtai"):
+async def generate_stream_response(request: ChatRequest, user_context: UserContext):
     session_id = request.session_id
     latest_user_msg = None
     try:
-        ai_config = get_config_by_app_name(app_name)
+        ai_config = get_config_by_app_name(user_context.app_name)
         if not ai_config:
-            raise ValueError(f"未找到appName '{app_name}' 的配置")
+            raise ValueError(f"未找到appName '{user_context.app_name}' 的配置")
 
-        client = get_client(app_name)
+        client = get_client(user_context.app_name)
         knowledge_id = ai_config["knowledgeId"]
 
         latest_user_msg = get_latest_user_message(request.messages)
@@ -37,7 +37,7 @@ async def generate_stream_response(request: ChatRequest, user_id: str, app_name:
 
         # 保存用户消息到 DB
         save_chat_history(
-            user_id=user_id,
+            user_id=user_context.user_id,
             session_id=session_id,
             role=latest_user_msg.role,
             content=latest_user_msg.content,
@@ -177,8 +177,10 @@ async def generate_stream_response(request: ChatRequest, user_id: str, app_name:
         system_prompt = {"role": "system", "content": [{"type": "input_text", "text": system_prompt}]}
 
         api_messages = [system_prompt, {"role": latest_user_msg.role, "content": latest_user_msg.content}]
-        tools = get_web_search_tools() + get_knowledge_search_tools(knowledge_id)
-        previous_response_id = get_previous_response_id(user_id, session_id)
+        tools = get_web_search_tools()
+        if knowledge_id:
+            tools += get_knowledge_search_tools(knowledge_id)
+        previous_response_id = get_previous_response_id(user_context.user_id, session_id)
 
         stream = client.responses.create(
             model=config.MODEL_NAME,
@@ -262,7 +264,7 @@ async def generate_stream_response(request: ChatRequest, user_id: str, app_name:
                 if response_obj and hasattr(response_obj, 'id'):
                     response_id = response_obj.id
                 save_chat_log(
-                    user_id=user_id,
+                    user_id=user_context.user_id,
                     question=latest_user_msg.content,
                     stream_mode=True,
                     raw_response=repr(response_obj),
@@ -274,7 +276,7 @@ async def generate_stream_response(request: ChatRequest, user_id: str, app_name:
         if accumulated_content:
             # 保存助手消息到 DB(含 thinking / searching)
             save_chat_history(
-                user_id=user_id,
+                user_id=user_context.user_id,
                 session_id=session_id,
                 role="assistant",
                 content=accumulated_content,
@@ -292,7 +294,7 @@ async def generate_stream_response(request: ChatRequest, user_id: str, app_name:
             "timestamp": datetime.now().isoformat()
         }
         save_chat_log(
-            user_id=user_id,
+            user_id=user_context.user_id,
             question=latest_user_msg.content if latest_user_msg else "",
             stream_mode=True,
             status="error",
@@ -300,17 +302,17 @@ async def generate_stream_response(request: ChatRequest, user_id: str, app_name:
         )
         yield f"data: {json.dumps(error_response)}\n\n"
 
-# 以下是非流格式的输出, 采用了豆包助手工具,目前项目中没有使用到
+
+
 @router.post("/chat", response_model=ChatResponse)
 async def chat(
     request: ChatRequest,
-    user_id: Annotated[str, Depends(resolve_user_id)],
-    app_name: str = Query(default="com.yunxiangshengtai", description="应用包名"),
+    user_context: UserContext = Depends(resolve_user_id),
 ):
     try:
         if request.stream:
             return StreamingResponse(
-                generate_stream_response(request, user_id, app_name),
+                generate_stream_response(request, UserContext(user_id=user_id, app_name=app_name)),
                 media_type="text/plain",
                 headers={
                     "Cache-Control": "no-cache",
@@ -318,21 +320,21 @@ async def chat(
                     "Content-Type": "text/event-stream",
                 }
             )
-
+        # 以下是非流格式的输出, 采用了豆包助手工具,目前项目中没有使用到
         # 以下是非流式输出处理
         session_id = request.session_id
         latest_user_msg = get_latest_user_message(request.messages)
         if not latest_user_msg:
             raise ValueError("请求中没有找到user角色的消息")
 
-        ai_config = get_config_by_app_name(app_name)
+        ai_config = get_config_by_app_name(user_context.app_name)
         if not ai_config:
-            raise ValueError(f"未找到appName '{app_name}' 的配置")
+            raise ValueError(f"未找到appName '{user_context.app_name}' 的配置")
 
-        client = get_client(app_name)
+        client = get_client(user_context.app_name)
 
         save_chat_history(
-            user_id=user_id,
+            user_id=user_context.user_id,
             session_id=session_id,
             role=latest_user_msg.role,
             content=latest_user_msg.content,
@@ -341,7 +343,7 @@ async def chat(
 
         api_messages = [{"role": latest_user_msg.role, "content": latest_user_msg.content}]
         tools = get_doubao_tools()
-        previous_response_id = get_previous_response_id(user_id, session_id)
+        previous_response_id = get_previous_response_id(user_context.user_id, session_id)
 
         response = client.responses.create(
             model=config.MODEL_NAME,
@@ -353,7 +355,7 @@ async def chat(
         )
 
         save_chat_log(
-            user_id=user_id,
+            user_id=user_context.user_id,
             question=latest_user_msg.content,
             stream_mode=False,
             raw_response=repr(response),
@@ -384,7 +386,7 @@ async def chat(
 
         now = datetime.now()
         save_chat_history(
-            user_id=user_id,
+            user_id=user_context.user_id,
             session_id=session_id,
             role="assistant",
             content=message_content,
@@ -410,7 +412,7 @@ async def chat(
     except Exception as e:
         error_message = f"处理聊天请求时发生错误: {str(e)}"
         save_chat_log(
-            user_id=user_id,
+            user_id=user_context.user_id,
             question=request.messages[-1].content if request.messages else "",
             stream_mode=request.stream,
             status="error",
@@ -418,24 +420,6 @@ async def chat(
         )
         raise HTTPException(status_code=500, detail=error_message)
 
-#
-# @router.get("/models")
-# async def get_models(current_user: Annotated[User, Depends(get_current_active_user)]):
-#     try:
-#         models = client.models.list()
-#         return {
-#             "models": [model.id for model in models.data],
-#             "default_model": config.MODEL_NAME,
-#             "user": current_user.username
-#         }
-#     except Exception:
-#         return {
-#             "models": [config.MODEL_NAME],
-#             "default_model": config.MODEL_NAME,
-#             "note": "使用默认模型配置",
-#             "user": current_user.username
-#         }
-
 
 @router.get("/history")
 async def get_user_history(