auth.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. # -*- coding: utf-8 -*-
  2. """
  3. 认证模块 —— 通过请求头 x-access-token 验证用户登录状态
  4. 调用 VENT_SYSTEM_BASE_URL + "/sys/user/getUserInfo",
  5. 将客户端请求头中的 x-access-token 转发到通风系统进行身份验证。
  6. """
  7. import os
  8. import httpx
  9. from fastapi import HTTPException, Request
  10. # ── 通风系统认证服务地址 ──
  11. VENT_SYSTEM_BASE_URL = os.getenv("VENT_SYSTEM_BASE_URL", "").strip()
  12. async def get_current_user(request: Request) -> dict:
  13. """FastAPI 依赖项:从请求头 x-access-token 验证用户登录状态。
  14. 验证流程:
  15. 1. 从 HTTP 请求头中提取 x-access-token
  16. 2. 转发到通风系统 GET /sys/user/getUserInfo
  17. 3. 若响应 success=false 或无 userInfo 则抛出 401
  18. Returns:
  19. dict: 用户信息(取自 result.userInfo)
  20. Raises:
  21. HTTPException 401: 未登录或令牌无效
  22. HTTPException 502: 认证服务不可用
  23. HTTPException 504: 认证服务超时
  24. """
  25. # ── 1. 提取令牌 ──
  26. token = request.headers.get("x-access-token")
  27. if not token:
  28. raise HTTPException(status_code=401, detail="缺少认证令牌")
  29. # ── 2. 检查后端地址配置 ──
  30. if not VENT_SYSTEM_BASE_URL:
  31. raise HTTPException(status_code=500, detail="认证服务地址未配置 (VENT_SYSTEM_BASE_URL)")
  32. url = f"{VENT_SYSTEM_BASE_URL}/sys/user/getUserInfo"
  33. # ── 3. 转发令牌到通风系统验证 ──
  34. try:
  35. async with httpx.AsyncClient(timeout=10.0) as client:
  36. resp = await client.get(url, headers={"x-access-token": token})
  37. data = resp.json()
  38. except httpx.ConnectError as e:
  39. raise HTTPException(status_code=502, detail=f"认证服务连接失败: {e}")
  40. except httpx.TimeoutException:
  41. raise HTTPException(status_code=504, detail="认证服务响应超时")
  42. except httpx.HTTPStatusError as e:
  43. raise HTTPException(status_code=502, detail=f"认证服务返回错误: {e.response.status_code}")
  44. except Exception as e:
  45. raise HTTPException(status_code=502, detail=f"认证服务异常: {e}")
  46. # ── 4. 校验响应 ──
  47. if not isinstance(data, dict) or not data.get("success"):
  48. raise HTTPException(status_code=401, detail="未登录或令牌已过期")
  49. user_info = data.get("result", {}).get("userInfo")
  50. if not user_info:
  51. raise HTTPException(status_code=401, detail="未登录或令牌已过期")
  52. print(f"[认证] {user_info.get('realname') or user_info.get('username')} | {user_info.get('username')} | {user_info.get('orgCode','?')}")
  53. return user_info