Ai_GirlFriend/lover/deps.py
2026-02-02 20:08:28 +08:00

137 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from typing import Optional
import requests
from fastapi import Header, HTTPException, status, Cookie
from pydantic import BaseModel
from .config import settings
class AuthedUser(BaseModel):
id: int
reg_step: int = 1
gender: int = 0 # 0/1/2
nickname: str = ""
token: str = ""
def _fetch_user_from_php(token: str) -> Optional[dict]:
"""通过 PHP/FastAdmin 接口获取用户信息。"""
import logging
logger = logging.getLogger(__name__)
logger.info(f"用户中心调试 - 调用接口: {settings.USER_INFO_API}")
logger.info(f"用户中心调试 - token: {token}")
try:
resp = requests.get(
settings.USER_INFO_API,
headers={"token": token},
timeout=5,
)
logger.info(f"用户中心调试 - 响应状态码: {resp.status_code}")
logger.info(f"用户中心调试 - 响应内容: {resp.text[:200]}...")
except Exception as exc: # 网络/超时
logger.error(f"用户中心调试 - 请求异常: {exc}")
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail="用户中心接口不可用",
) from exc
if resp.status_code != 200:
logger.error(f"用户中心调试 - 状态码非200: {resp.status_code}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户中心返回非 200",
)
data = resp.json()
logger.info(f"用户中心调试 - 解析JSON成功: {data}")
# 兼容常见 FastAdmin 响应结构
if isinstance(data, dict):
payload = data.get("data") or data.get("user") or data
else:
payload = None
if not payload:
logger.error(f"用户中心调试 - 未找到用户数据: {data}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户中心未返回用户信息",
)
return payload
def get_current_user(
authorization: Optional[str] = Header(default=None),
x_token: Optional[str] = Header(default=None, alias="X-Token"),
token_header: Optional[str] = Header(default=None, alias="token"),
token_cookie: Optional[str] = Cookie(default=None, alias="token"),
x_user_id: Optional[int] = Header(default=None, alias="X-User-Id"),
):
"""
鉴权顺序:
1) Authorization: Bearer <token>
2) X-Token: <token>
3) token: <token> (header)
4) token: <token> (cookie)
5) X-User-Id仅调试用不经过 PHP 鉴权)
生产流程:直接调用 USER_INFO_API 拉取用户信息,不再依赖本地 nf_user 缓存。
"""
import logging
logger = logging.getLogger(__name__)
logger.info(f"认证调试 - APP_ENV: {settings.APP_ENV}, DEBUG: {settings.DEBUG}")
logger.info(f"认证调试 - authorization: {authorization}, x_token: {x_token}, token_header: {token_header}, token_cookie: {token_cookie}, x_user_id: {x_user_id}")
token = None
if authorization and authorization.lower().startswith("bearer "):
token = authorization.split(" ", 1)[1].strip()
if not token and x_token:
token = x_token
if not token and token_header:
token = token_header
if not token and token_cookie:
token = token_cookie
logger.info(f"认证调试 - 提取的 token: {token}")
if token:
try:
payload = _fetch_user_from_php(token)
user_id = payload.get("id") or payload.get("user_id")
reg_step = payload.get("reg_step") or payload.get("stage") or 1
gender = payload.get("gender") or 0
nickname = payload.get("nickname") or payload.get("username") or ""
# 开发环境:自动提升 reg_step 到 2方便测试
if settings.APP_ENV == "development" and settings.DEBUG and reg_step < 2:
logger.warning(f"开发环境:用户 reg_step={reg_step},自动提升到 2")
reg_step = 2
if not user_id:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="用户中心缺少用户ID"
)
return AuthedUser(
id=user_id,
reg_step=reg_step,
gender=gender,
nickname=nickname,
token=token,
)
except HTTPException as e:
# 如果是开发环境token 验证失败时也返回测试用户
if settings.APP_ENV == "development" and settings.DEBUG:
logger.warning(f"开发环境token 验证失败({e.detail}),使用测试用户")
return AuthedUser(id=70, reg_step=2, gender=0, nickname="test-user", token="")
raise
# 调试兜底:仅凭 X-User-Id 不校验 PHP方便联调
if x_user_id is not None:
return AuthedUser(id=x_user_id, reg_step=2, gender=0, nickname="debug-user", token="")
# 开发环境兜底:如果没有任何认证信息,返回默认测试用户
if settings.APP_ENV == "development" and settings.DEBUG:
return AuthedUser(id=70, reg_step=2, gender=0, nickname="test-user", token="")
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在或未授权")