deps.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. """
  2. 依赖注入
  3. """
  4. from fastapi import Depends, HTTPException, status, Request
  5. from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
  6. from sqlalchemy.orm import Session
  7. from typing import Optional
  8. from app.database import get_db
  9. from app.core.security import verify_token
  10. from app.models.admin import Admin
  11. from app.models.user import User
  12. from app.models.session import Session
  13. from app.services.session_service import SessionService
  14. security = HTTPBearer()
  15. def get_current_admin(
  16. credentials: HTTPAuthorizationCredentials = Depends(security),
  17. db: Session = Depends(get_db)
  18. ) -> Admin:
  19. """获取当前管理员"""
  20. token = credentials.credentials
  21. payload = verify_token(token)
  22. if not payload:
  23. raise HTTPException(
  24. status_code=status.HTTP_401_UNAUTHORIZED,
  25. detail="无效的令牌"
  26. )
  27. username = payload.get("sub")
  28. admin = db.query(Admin).filter(Admin.username == username).first()
  29. if not admin or admin.status != 1:
  30. raise HTTPException(
  31. status_code=status.HTTP_401_UNAUTHORIZED,
  32. detail="管理员不存在或已被禁用"
  33. )
  34. return admin
  35. def get_current_user_session(
  36. request: Request,
  37. db: Session = Depends(get_db),
  38. allow_expired_extend: bool = False
  39. ) -> tuple[User, Session]:
  40. """
  41. 获取当前用户会话
  42. 从请求头或查询参数中获取session_id,验证并返回用户和会话信息
  43. Args:
  44. allow_expired_extend: 是否允许延长已过期的活跃Session(用于心跳场景)
  45. Returns:
  46. tuple: (User对象, Session对象)
  47. """
  48. # 从请求头获取session_id
  49. session_id = request.headers.get("X-Session-ID")
  50. # 如果请求头中没有,从查询参数获取
  51. if not session_id:
  52. session_id = request.query_params.get("session_id")
  53. # 如果都没有,从请求体中获取(针对加密请求)
  54. if not session_id:
  55. # 对于加密请求,session_id会在解密后的数据中
  56. # 这里先设置为空,后续在接口中处理
  57. pass
  58. if not session_id:
  59. raise HTTPException(
  60. status_code=status.HTTP_401_UNAUTHORIZED,
  61. detail="缺少会话ID"
  62. )
  63. # 验证会话(根据是否为心跳请求决定是否允许延长过期Session)
  64. is_valid, session, error_msg = SessionService.validate_session(db, session_id, allow_expired_extend=allow_expired_extend)
  65. if not is_valid:
  66. raise HTTPException(
  67. status_code=status.HTTP_401_UNAUTHORIZED,
  68. detail=f"会话验证失败: {error_msg}"
  69. )
  70. # 获取用户信息
  71. user = db.query(User).filter(User.id == session.user_id).first()
  72. if not user:
  73. raise HTTPException(
  74. status_code=status.HTTP_401_UNAUTHORIZED,
  75. detail="用户不存在"
  76. )
  77. # 验证header中的user_id和user_name是否与session匹配(组合校验)
  78. header_user_id = request.headers.get("x-user-id") or request.headers.get("X-User-Id")
  79. header_user_name = request.headers.get("x-user-name") or request.headers.get("X-User-Name")
  80. if header_user_id and header_user_name:
  81. try:
  82. header_user_id = int(header_user_id)
  83. if header_user_id != user.id or header_user_name != user.username:
  84. raise HTTPException(
  85. status_code=status.HTTP_401_UNAUTHORIZED,
  86. detail="用户信息校验失败"
  87. )
  88. except ValueError:
  89. raise HTTPException(
  90. status_code=status.HTTP_401_UNAUTHORIZED,
  91. detail="用户信息格式错误"
  92. )
  93. else:
  94. # 如果没有提供header用户信息,认为是认证失败
  95. raise HTTPException(
  96. status_code=status.HTTP_401_UNAUTHORIZED,
  97. detail="缺少用户信息"
  98. )
  99. return user, session
  100. def get_current_user_session_for_heartbeat(
  101. request: Request,
  102. db: Session = Depends(get_db)
  103. ) -> tuple[User, Session]:
  104. """
  105. 获取当前用户会话(心跳专用)
  106. 允许延长已过期的活跃Session,保持用户在线体验
  107. """
  108. return get_current_user_session(request, db, allow_expired_extend=True)
  109. def get_optional_user_session(
  110. request: Request,
  111. db: Session = Depends(get_db)
  112. ) -> Optional[tuple[User, Session]]:
  113. """
  114. 获取可选的用户会话(用于不需要强制登录的接口)
  115. Returns:
  116. Optional[tuple[User, Session]]: 用户和会话信息,如果没有则返回None
  117. """
  118. try:
  119. return get_current_user_session(request, db)
  120. except HTTPException:
  121. return None