""" 认证路由 处理用户登录、登出、Token 验证 """ from fastapi import APIRouter, Depends, HTTPException, status from datetime import timedelta from ..models import ( LoginRequest, TokenResponse, TokenVerifyRequest, TokenVerifyResponse ) from ..deps import ( get_current_user, authenticate_user, create_access_token, ACCESS_TOKEN_EXPIRE_MINUTES ) import logging logger = logging.getLogger(__name__) router = APIRouter() @router.post("/login", response_model=TokenResponse) async def login(login_request: LoginRequest): """ 用户登录 - **username**: 用户名 - **password**: 密码 返回 JWT Token """ # 验证用户凭证 user = authenticate_user(login_request.username, login_request.password) if not user: logger.warning(f"Failed login attempt for user: {login_request.username}") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) # 创建 Token access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": user["username"], "is_active": user["is_active"]}, expires_delta=access_token_expires ) logger.info(f"User logged in: {user['username']}") return TokenResponse( access_token=access_token, token_type="bearer", expires_in=ACCESS_TOKEN_EXPIRE_MINUTES * 60 ) @router.post("/verify", response_model=TokenVerifyResponse) async def verify_token( verify_request: TokenVerifyRequest ): """ 验证 Token 有效性 - **token**: JWT Token 返回 Token 是否有效及用户信息 """ from ..deps import verify_token as do_verify_token try: payload = do_verify_token(verify_request.token) username = payload.get("sub") return TokenVerifyResponse( valid=True, user_info={ "username": username, "is_active": payload.get("is_active", True), "exp": payload.get("exp") } ) except HTTPException: return TokenVerifyResponse(valid=False, user_info=None) @router.get("/me") async def get_current_user_info(current_user: dict = Depends(get_current_user)): """ 获取当前用户信息 需要有效的 JWT Token """ return { "username": current_user["username"], "is_active": current_user["is_active"], "exp": current_user.get("exp") } @router.post("/logout") async def logout(current_user: dict = Depends(get_current_user)): """ 用户登出 注:JWT 是无状态的,客户端只需删除 Token 即可 此接口主要用于记录日志或执行清理操作 """ username = current_user.get("username", "unknown") logger.info(f"User logged out: {username}") return {"message": "Successfully logged out"}