优化登录相关逻辑

This commit is contained in:
jingrow 2025-11-05 06:04:03 +08:00
parent 85cc38e0ed
commit 02c09fa975
2 changed files with 119 additions and 136 deletions

View File

@ -1,4 +1,4 @@
from fastapi import APIRouter, HTTPException, Request from fastapi import APIRouter, HTTPException, Request, Depends
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from pydantic import BaseModel from pydantic import BaseModel
from typing import Optional from typing import Optional
@ -28,49 +28,68 @@ class UserInfoResponse(BaseModel):
user_info: Optional[dict] = None user_info: Optional[dict] = None
message: Optional[str] = None message: Optional[str] = None
# Cookie配置常量
COOKIE_CONFIG = {
"httponly": True,
"samesite": "lax",
"secure": False, # 开发环境可以设为False生产环境建议设为True
"path": "/"
}
# 需要清除的cookie列表
COOKIES_TO_CLEAR = ["sid", "user_id", "user_image", "full_name", "system_user"]
def get_session_cookie(request: Request) -> Optional[str]:
"""从请求中获取session cookie并设置contextFastAPI依赖注入"""
session_cookie = request.cookies.get('sid')
if session_cookie:
set_context({"session_cookie": session_cookie})
return session_cookie
def handle_auth_result(result: dict, error_status_code: int = 400):
"""统一处理认证结果,成功返回数据,失败抛出异常"""
if not result.get("success"):
raise HTTPException(
status_code=error_status_code,
detail=result.get("message", "操作失败")
)
return result
def create_response_with_cookie(data: dict, session_cookie: Optional[str] = None) -> JSONResponse:
"""创建响应并设置cookie"""
response = JSONResponse(content=data)
if session_cookie:
response.set_cookie(key="sid", value=session_cookie, **COOKIE_CONFIG)
return response
def create_response_clear_cookies(data: dict) -> JSONResponse:
"""创建响应并清除所有相关cookie"""
response = JSONResponse(content=data)
for cookie_name in COOKIES_TO_CLEAR:
cookie_kwargs = COOKIE_CONFIG.copy()
if cookie_name == "sid":
cookie_kwargs.pop("secure", None) # delete_cookie不需要secure参数
response.delete_cookie(key=cookie_name, **cookie_kwargs)
return response
@router.post("/jingrow/login", response_model=LoginResponse) @router.post("/jingrow/login", response_model=LoginResponse)
async def login_route(request: Request, login_data: LoginRequest): async def login_route(login_data: LoginRequest):
""" """登录路由"""
登录路由
"""
try: try:
# 调用登录函数
result = login(login_data.username, login_data.password) result = login(login_data.username, login_data.password)
handle_auth_result(result, error_status_code=401)
if result.get("success"): session_cookie = result.get("session_cookie")
session_cookie = result.get("session_cookie") user_info_result = get_user_info(session_cookie)
user_info = user_info_result.get("user_info") if user_info_result.get("success") else None
# 获取用户信息
user_info_result = get_user_info(session_cookie) response_data = {
user_info = None "success": True,
if user_info_result.get("success"): "message": result.get("message", "Logged In"),
user_info = user_info_result.get("user_info") "user": user_info
}
# 创建响应
response_data = { return create_response_with_cookie(response_data, session_cookie)
"success": True,
"message": result.get("message", "Logged In"),
"user": user_info
}
# 创建响应并设置cookie
response = JSONResponse(content=response_data)
if session_cookie:
response.set_cookie(
key="sid",
value=session_cookie,
httponly=True,
samesite="lax",
secure=False, # 开发环境可以设为False生产环境建议设为True
path="/"
)
return response
else:
raise HTTPException(
status_code=401,
detail=result.get("message", "登录失败")
)
except HTTPException: except HTTPException:
raise raise
except Exception as e: except Exception as e:
@ -78,39 +97,18 @@ async def login_route(request: Request, login_data: LoginRequest):
raise HTTPException(status_code=500, detail=f"登录异常: {str(e)}") raise HTTPException(status_code=500, detail=f"登录异常: {str(e)}")
@router.post("/jingrow/logout", response_model=LogoutResponse) @router.post("/jingrow/logout", response_model=LogoutResponse)
async def logout_route(request: Request): async def logout_route(session_cookie: Optional[str] = Depends(get_session_cookie)):
""" """登出路由"""
登出路由
"""
try: try:
# 从cookie获取session
session_cookie = request.cookies.get('sid')
# 设置context以便logout函数可以使用
if session_cookie:
set_context({"session_cookie": session_cookie})
# 调用登出函数
result = logout(session_cookie) result = logout(session_cookie)
handle_auth_result(result, error_status_code=400)
if result.get("success"): response_data = {
# 创建响应并清除cookie "success": True,
response = JSONResponse(content={ "message": result.get("message", "登出成功")
"success": True, }
"message": result.get("message", "登出成功")
}) return create_response_clear_cookies(response_data)
# 清除所有相关的cookie需要设置path="/"才能正确删除)
response.delete_cookie(key="sid", path="/", httponly=True, samesite="lax")
response.delete_cookie(key="user_id", path="/")
response.delete_cookie(key="user_image", path="/")
response.delete_cookie(key="full_name", path="/")
response.delete_cookie(key="system_user", path="/")
return response
else:
raise HTTPException(
status_code=400,
detail=result.get("message", "登出失败")
)
except HTTPException: except HTTPException:
raise raise
except Exception as e: except Exception as e:
@ -118,31 +116,16 @@ async def logout_route(request: Request):
raise HTTPException(status_code=500, detail=f"登出异常: {str(e)}") raise HTTPException(status_code=500, detail=f"登出异常: {str(e)}")
@router.get("/jingrow/user-info", response_model=UserInfoResponse) @router.get("/jingrow/user-info", response_model=UserInfoResponse)
async def get_user_info_route(request: Request): async def get_user_info_route(session_cookie: Optional[str] = Depends(get_session_cookie)):
""" """获取用户信息路由"""
获取用户信息路由
"""
try: try:
# 从cookie获取session
session_cookie = request.cookies.get('sid')
# 设置context以便get_user_info函数可以使用
if session_cookie:
set_context({"session_cookie": session_cookie})
# 调用获取用户信息函数
result = get_user_info(session_cookie) result = get_user_info(session_cookie)
handle_auth_result(result, error_status_code=401)
if result.get("success"): return {
return { "success": True,
"success": True, "user_info": result.get("user_info")
"user_info": result.get("user_info") }
}
else:
raise HTTPException(
status_code=401,
detail=result.get("message", "获取用户信息失败")
)
except HTTPException: except HTTPException:
raise raise
except Exception as e: except Exception as e:

View File

@ -2,6 +2,7 @@ import threading
import sys import sys
import os import os
import requests import requests
from typing import Optional
# 导入配置 # 导入配置
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))) sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))))
@ -64,6 +65,36 @@ def get_jingrow_cloud_api_headers():
return headers return headers
def _extract_session_cookie_from_response(response: requests.Response, session: requests.Session) -> Optional[str]:
"""从响应中提取session cookie"""
session_cookie = None
if 'Set-Cookie' in response.headers:
cookies = response.headers['Set-Cookie']
if 'sid=' in cookies:
session_cookie = cookies.split('sid=')[1].split(';')[0]
# 如果没有从Set-Cookie获取尝试从session的cookies获取
if not session_cookie:
session_cookie = session.cookies.get('sid')
return session_cookie
def _call_jingrow_api(method: str, endpoint: str, session_cookie: Optional[str] = None, **kwargs) -> requests.Response:
"""调用Jingrow API的通用函数"""
url = f"{Config.jingrow_server_url}{endpoint}"
headers = kwargs.pop('headers', {})
# 如果没有提供session_cookie尝试从context获取
if not session_cookie:
context = getattr(_thread_local, 'context', None)
if context:
session_cookie = context.get('session_cookie')
if session_cookie:
headers["Cookie"] = f"sid={session_cookie}"
return requests.request(method.upper(), url, headers=headers, timeout=30, **kwargs)
def login(username: str, password: str) -> dict: def login(username: str, password: str) -> dict:
""" """
登录函数调用jingrow框架的登录API 登录函数调用jingrow框架的登录API
@ -95,17 +126,7 @@ def login(username: str, password: str) -> dict:
if response.status_code == 200: if response.status_code == 200:
result = response.json() result = response.json()
if result.get("message") == "Logged In": if result.get("message") == "Logged In":
# 获取session cookie session_cookie = _extract_session_cookie_from_response(response, session)
session_cookie = None
if 'Set-Cookie' in response.headers:
cookies = response.headers['Set-Cookie']
if 'sid=' in cookies:
session_cookie = cookies.split('sid=')[1].split(';')[0]
# 如果没有从Set-Cookie获取尝试从session的cookies获取
if not session_cookie:
session_cookie = session.cookies.get('sid')
return { return {
"success": True, "success": True,
"message": result.get("message", "Logged In"), "message": result.get("message", "Logged In"),
@ -134,7 +155,7 @@ def login(username: str, password: str) -> dict:
"message": f"登录异常: {str(e)}" "message": f"登录异常: {str(e)}"
} }
def logout(session_cookie: str = None) -> dict: def logout(session_cookie: Optional[str] = None) -> dict:
""" """
登出函数调用jingrow框架的登出API 登出函数调用jingrow框架的登出API
@ -145,21 +166,7 @@ def logout(session_cookie: str = None) -> dict:
dict: 登出结果包含success和message字段 dict: 登出结果包含success和message字段
""" """
try: try:
url = f"{Config.jingrow_server_url}/api/action/logout" response = _call_jingrow_api('GET', '/api/action/logout', session_cookie, headers={"Accept": "application/json"})
headers = {
"Accept": "application/json"
}
# 如果没有提供session_cookie尝试从context获取
if not session_cookie:
context = getattr(_thread_local, 'context', None)
if context:
session_cookie = context.get('session_cookie')
if session_cookie:
headers["Cookie"] = f"sid={session_cookie}"
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200: if response.status_code == 200:
return { return {
@ -177,7 +184,7 @@ def logout(session_cookie: str = None) -> dict:
"message": f"登出异常: {str(e)}" "message": f"登出异常: {str(e)}"
} }
def get_user_info(session_cookie: str = None) -> dict: def get_user_info(session_cookie: Optional[str] = None) -> dict:
""" """
获取用户信息函数调用jingrow框架的get_user_info API 获取用户信息函数调用jingrow框架的get_user_info API
@ -188,22 +195,15 @@ def get_user_info(session_cookie: str = None) -> dict:
dict: 用户信息包含success和user_info字段 dict: 用户信息包含success和user_info字段
""" """
try: try:
url = f"{Config.jingrow_server_url}/api/action/jingrow.realtime.get_user_info" response = _call_jingrow_api(
headers = { 'GET',
"Accept": "application/json", '/api/action/jingrow.realtime.get_user_info',
"Content-Type": "application/json" session_cookie,
} headers={
"Accept": "application/json",
# 如果没有提供session_cookie尝试从context获取 "Content-Type": "application/json"
if not session_cookie: }
context = getattr(_thread_local, 'context', None) )
if context:
session_cookie = context.get('session_cookie')
if session_cookie:
headers["Cookie"] = f"sid={session_cookie}"
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200: if response.status_code == 200:
data = response.json() data = response.json()