| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- """
- 依赖注入
- """
- from fastapi import Depends, HTTPException, status, Request
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
- from sqlalchemy.orm import Session
- from typing import Optional
- from app.database import get_db
- from app.core.security import verify_token
- from app.models.admin import Admin
- from app.models.user import User
- from app.models.session import Session
- from app.services.session_service import SessionService
- security = HTTPBearer()
- def get_current_admin(
- credentials: HTTPAuthorizationCredentials = Depends(security),
- db: Session = Depends(get_db)
- ) -> Admin:
- """获取当前管理员"""
- token = credentials.credentials
- payload = verify_token(token)
- if not payload:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="无效的令牌"
- )
-
- username = payload.get("sub")
- admin = db.query(Admin).filter(Admin.username == username).first()
- if not admin or admin.status != 1:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="管理员不存在或已被禁用"
- )
-
- return admin
- def get_current_user_session(
- request: Request,
- db: Session = Depends(get_db),
- allow_expired_extend: bool = False
- ) -> tuple[User, Session]:
- """
- 获取当前用户会话
- 从请求头或查询参数中获取session_id,验证并返回用户和会话信息
- Args:
- allow_expired_extend: 是否允许延长已过期的活跃Session(用于心跳场景)
- Returns:
- tuple: (User对象, Session对象)
- """
- # 从请求头获取session_id
- session_id = request.headers.get("X-Session-ID")
- # 如果请求头中没有,从查询参数获取
- if not session_id:
- session_id = request.query_params.get("session_id")
- # 如果都没有,从请求体中获取(针对加密请求)
- if not session_id:
- # 对于加密请求,session_id会在解密后的数据中
- # 这里先设置为空,后续在接口中处理
- pass
- if not session_id:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="缺少会话ID"
- )
- # 验证会话(根据是否为心跳请求决定是否允许延长过期Session)
- is_valid, session, error_msg = SessionService.validate_session(db, session_id, allow_expired_extend=allow_expired_extend)
- if not is_valid:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail=f"会话验证失败: {error_msg}"
- )
- # 获取用户信息
- user = db.query(User).filter(User.id == session.user_id).first()
- if not user:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="用户不存在"
- )
- # 验证header中的user_id和user_name是否与session匹配(组合校验)
- header_user_id = request.headers.get("x-user-id") or request.headers.get("X-User-Id")
- header_user_name = request.headers.get("x-user-name") or request.headers.get("X-User-Name")
- if header_user_id and header_user_name:
- try:
- header_user_id = int(header_user_id)
- if header_user_id != user.id or header_user_name != user.username:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="用户信息校验失败"
- )
- except ValueError:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="用户信息格式错误"
- )
- else:
- # 如果没有提供header用户信息,认为是认证失败
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="缺少用户信息"
- )
- return user, session
- def get_current_user_session_for_heartbeat(
- request: Request,
- db: Session = Depends(get_db)
- ) -> tuple[User, Session]:
- """
- 获取当前用户会话(心跳专用)
- 允许延长已过期的活跃Session,保持用户在线体验
- """
- return get_current_user_session(request, db, allow_expired_extend=True)
- def get_optional_user_session(
- request: Request,
- db: Session = Depends(get_db)
- ) -> Optional[tuple[User, Session]]:
- """
- 获取可选的用户会话(用于不需要强制登录的接口)
- Returns:
- Optional[tuple[User, Session]]: 用户和会话信息,如果没有则返回None
- """
- try:
- return get_current_user_session(request, db)
- except HTTPException:
- return None
|