""" 认证相关API路由 """ from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, status, Header from fastapi.security import HTTPBearer from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_db, get_current_user from app.schemas.user import ( LoginRequest, LoginResponse, RefreshTokenRequest, RefreshTokenResponse, ChangePasswordRequest, ) from app.services.auth_service import auth_service from app.models.user import User from app.core.response import success_response from app.core.config import settings from jose import jwt import logging logger = logging.getLogger(__name__) router = APIRouter() security = HTTPBearer() @router.post("/login") async def login( credentials: LoginRequest, db: AsyncSession = Depends(get_db) ): """ 用户登录 - **username**: 用户名 - **password**: 密码 - **captcha**: 验证码 - **captcha_key**: 验证码UUID """ result = await auth_service.login( db=db, username=credentials.username, password=credentials.password, captcha=credentials.captcha, captcha_key=credentials.captcha_key ) return success_response(data=result) @router.post("/refresh") async def refresh_token( token_request: RefreshTokenRequest, db: AsyncSession = Depends(get_db) ): """ 刷新访问令牌 - **refresh_token**: 刷新令牌 """ result = await auth_service.refresh_token( db=db, refresh_token=token_request.refresh_token ) return success_response(data=result) @router.post("/logout") async def logout( current_user: User = Depends(get_current_user), authorization: str = Header(...), db: AsyncSession = Depends(get_db) ): """ 用户登出 """ from app.utils.redis_client import redis_client # 提取Token token = authorization.replace("Bearer ", "") # 获取Token剩余有效期 try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) exp = payload.get("exp") if exp: # 计算剩余秒数 remaining_time = int(exp) - int(datetime.utcnow().timestamp()) if remaining_time > 0: # 将Token加入黑名单 await redis_client.setex( f"blacklist:{token}", remaining_time, "1" ) except Exception as e: logger.error(f"Token黑名单添加失败: {str(e)}") return success_response(message="登出成功") @router.put("/change-password") async def change_password( password_data: ChangePasswordRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): """ 修改密码 - **old_password**: 旧密码 - **new_password**: 新密码 - **confirm_password**: 确认密码 """ await auth_service.change_password( db=db, user=current_user, old_password=password_data.old_password, new_password=password_data.new_password ) return success_response(message="密码修改成功") @router.get("/captcha") async def get_captcha(): """ 获取验证码 返回验证码图片和captcha_key """ captcha_data = await auth_service._generate_captcha() return success_response(data={ "captcha_key": captcha_data["captcha_key"], "captcha_image": captcha_data["captcha_base64"] })