优化登录相关逻辑
This commit is contained in:
parent
85cc38e0ed
commit
02c09fa975
@ -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并设置context(FastAPI依赖注入)"""
|
||||||
|
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:
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user