# -*- coding: utf-8 -*- from typing import Union, Dict from fastapi import APIRouter, Depends, Request from fastapi.responses import JSONResponse from sqlalchemy.ext.asyncio import AsyncSession from redis.asyncio.client import Redis from app.common.response import ErrorResponse, SuccessResponse from app.core.router_class import OperationLogRoute from app.core.security import CustomOAuth2PasswordRequestForm from app.core.logger import log from app.config.setting import settings from app.core.dependencies import ( db_getter, get_current_user, redis_getter ) from .service import ( LoginService, CaptchaService ) from .schema import ( CaptchaOutSchema, JWTOutSchema, RefreshTokenPayloadSchema, LogoutPayloadSchema ) AuthRouter = APIRouter(route_class=OperationLogRoute, prefix="/auth", tags=["认证授权"]) @AuthRouter.post("/login", summary="登录", description="登录", response_model=JWTOutSchema) async def login_for_access_token_controller( request: Request, redis: Redis = Depends(redis_getter), login_form: CustomOAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(db_getter), ) -> Union[JSONResponse, Dict]: """ 用户登录 参数: - request (Request): FastAPI请求对象 - login_form (CustomOAuth2PasswordRequestForm): 登录表单数据 - db (AsyncSession): 数据库会话对象 返回: - JWTOutSchema: 包含访问令牌和刷新令牌的响应模型 异常: - CustomException: 认证失败时抛出异常。 """ login_token = await LoginService.authenticate_user_service(request=request, redis=redis, login_form=login_form, db=db) log.info(f"用户{login_form.username}登录成功") # 如果是文档请求,则不记录日志:http://localhost:8000/api/v1/docs if settings.DOCS_URL in request.headers.get("referer", ""): return login_token.model_dump() return SuccessResponse(data=login_token.model_dump(), msg="登录成功") @AuthRouter.post("/token/refresh", summary="刷新token", description="刷新token", response_model=JWTOutSchema, dependencies=[Depends(get_current_user)]) async def get_new_token_controller( request: Request, payload: RefreshTokenPayloadSchema, db: AsyncSession = Depends(db_getter), redis: Redis = Depends(redis_getter) ) -> JSONResponse: """ 刷新token 参数: - request (Request): FastAPI请求对象 - payload (RefreshTokenPayloadSchema): 刷新令牌负载模型 返回: - JWTOutSchema: 包含新的访问令牌和刷新令牌的响应模型 异常: - CustomException: 刷新令牌失败时抛出异常。 """ # 解析当前的访问Token以获取用户名 new_token = await LoginService.refresh_token_service(db=db, request=request, redis=redis, refresh_token=payload) token_dict = new_token.model_dump() log.info(f"刷新token成功: {token_dict}") return SuccessResponse(data=token_dict, msg="刷新成功") @AuthRouter.get("/captcha/get", summary="获取验证码", description="获取登录验证码", response_model=CaptchaOutSchema) async def get_captcha_for_login_controller( redis: Redis = Depends(redis_getter) ) -> JSONResponse: """ 获取登录验证码 参数: - redis (Redis): Redis客户端对象 返回: - CaptchaOutSchema: 包含验证码图片和key的响应模型 异常: - CustomException: 获取验证码失败时抛出异常。 """ # 获取验证码 captcha = await CaptchaService.get_captcha_service(redis=redis) log.info(f"获取验证码成功") return SuccessResponse(data=captcha, msg="获取验证码成功") @AuthRouter.post('/logout', summary="退出登录", description="退出登录", dependencies=[Depends(get_current_user)]) async def logout_controller( payload: LogoutPayloadSchema, redis: Redis = Depends(redis_getter) ) -> JSONResponse: """ 退出登录 参数: - payload (LogoutPayloadSchema): 退出登录负载模型 - redis (Redis): Redis客户端对象 返回: - JSONResponse: 包含退出登录结果的响应模型 异常: - CustomException: 退出登录失败时抛出异常。 """ if await LoginService.logout_service(redis=redis, token=payload): log.info('退出成功') return SuccessResponse(msg='退出成功') return ErrorResponse(msg='退出失败')