from datetime import datetime, timedelta from typing import Optional import jwt from fastapi import HTTPException, status, Depends, Header from app.controllers.app_user import app_user_controller from app.core.token_blacklist import is_blacklisted from app.schemas.app_user import AppUserJWTPayload from app.settings import settings # JWT配置 SECRET_KEY = settings.SECRET_KEY ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # 7天 def create_app_user_access_token(user_id: int, phone: str) -> str: """ 为AppUser创建访问令牌 """ expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) to_encode = { "user_id": user_id, "phone": phone, "exp": expire } encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt def verify_app_user_token(token: str) -> Optional[AppUserJWTPayload]: """ 验证AppUser令牌 """ try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) user_id: int = payload.get("user_id") phone: str = payload.get("phone") exp: datetime = datetime.fromtimestamp(payload.get("exp")) if user_id is None or phone is None: return None return AppUserJWTPayload(user_id=user_id, phone=phone, exp=exp) except jwt.DecodeError: return None except jwt.ExpiredSignatureError: return None except Exception: return None async def get_current_app_user_id(token: str = Header(None)) -> int: """ 从令牌中获取当前AppUser ID """ credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="未登录,请重新登录", headers={"WWW-Authenticate": "Bearer"}, ) if not token: raise credentials_exception if token and token != "dev": try: if await is_blacklisted(token): raise credentials_exception except Exception: pass payload = verify_app_user_token(token) if payload is None: raise credentials_exception return payload.user_id async def get_current_app_user( current_user_id: int = Depends(get_current_app_user_id) ): """ 获取当前AppUser """ user = await app_user_controller.get_user_by_id(current_user_id) if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在或已被停用" ) return user