""" 认证相关API路由 """ from datetime import timedelta from typing import Any from fastapi import APIRouter, Depends, HTTPException, status, Request from fastapi.security import OAuth2PasswordRequestForm from loguru import logger from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.database import get_async_session from app.models.user import User from app.utils.helpers import create_access_token, create_refresh_token, verify_token router = APIRouter() @router.post("/login") async def login( form_data: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_async_session), request: Request = None ): """ 用户登录 """ logger.info(f"Login attempt for user: {form_data.username}") # 查询用户 user = await User.get_by_username(db, form_data.username) if not user: logger.warning(f"User not found: {form_data.username}") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) # 检查用户状态 if not user.status: logger.warning(f"User inactive: {form_data.username}") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User is inactive", headers={"WWW-Authenticate": "Bearer"}, ) # 验证密码 is_valid = await user.check_password(form_data.password) if not is_valid: logger.warning(f"Invalid password for user: {form_data.username}") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) # 生成token,使用用户ID作为subject access_token_expires = timedelta(minutes=settings.JWT_EXPIRE_MINUTES) access_token = create_access_token( subject=str(user.id), expires_delta=access_token_expires ) refresh_token = create_refresh_token(subject=str(user.id)) logger.info(f"User logged in successfully: {form_data.username}") return { "access_token": access_token, "token_type": "bearer", "expires_in": settings.JWT_EXPIRE_MINUTES * 60, "refresh_token": refresh_token, "user_info": { "id": user.id, "username": user.username, "nickname": user.nickname, "email": user.email, "entity_id": user.entity_id, "entity_type": user.entity_type, } } @router.post("/refresh") async def refresh_token(refresh_token: str): """ 刷新访问令牌 """ username = verify_token(refresh_token, "refresh") if not username: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token", ) access_token_expires = timedelta(minutes=settings.JWT_EXPIRE_MINUTES) access_token = create_access_token( subject=username, expires_delta=access_token_expires ) return {"access_token": access_token, "token_type": "bearer"} @router.post("/logout") async def logout(): """ 用户退出登录 """ return {"message": "Successfully logged out"}