Files
marquiz-metrics/app/api/v1/endpoints/auth.py
13orlov b05a6165aa
All checks were successful
continuous-integration/drone/push Build is passing
good release 2.0 code name: chiki-puki
2025-08-31 22:28:24 +01:00

87 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, HTTPException, status, Depends
from fastapi.responses import JSONResponse
import httpx
from loguru import logger
from typing import Annotated
from app.core.config import settings
from app.api.v1.schemas.auth import TokenRequest, TokenResponse, UserInfoResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
router = APIRouter()
bearer_scheme = HTTPBearer()
YANDEX_TOKEN_URL = "https://oauth.yandex.ru/token"
YANDEX_USERINFO_URL = "https://login.yandex.ru/info"
@router.post("/token", response_model=TokenResponse, summary="Обмен кода авторизации на токен доступа")
async def exchange_code_for_token(request: TokenRequest):
"""
Принимает временный 'code' от фронтенда, обменивает его на 'access_token'
у Яндекса и возвращает токен клиенту.
"""
logger.info("Attempting to exchange authorization code for an access token.")
payload = {
'grant_type': 'authorization_code',
'code': request.code,
'client_id': settings.YANDEX_CLIENT_ID,
'client_secret': settings.YANDEX_CLIENT_SECRET
}
try:
async with httpx.AsyncClient() as client:
response = await client.post(YANDEX_TOKEN_URL, data=payload)
response.raise_for_status()
token_data = response.json()
logger.success("Successfully received access token from Yandex.")
return TokenResponse(
access_token=token_data.get("access_token"),
token_type=token_data.get("token_type", "bearer")
)
except httpx.HTTPStatusError as e:
error_details = e.response.json()
logger.error(f"Yandex OAuth error: {e.response.status_code} - {error_details}")
raise HTTPException(
status_code=e.response.status_code,
detail=f"Yandex OAuth error: {error_details.get('error_description', 'Unknown error')}"
)
except Exception as e:
logger.opt(exception=True).error("An unexpected error occurred during token exchange.")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An internal server error occurred."
)
@router.get("/userinfo", response_model=UserInfoResponse, summary="Получение информации о пользователе")
async def get_user_info(credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)]):
"""
Используя access_token, получает информацию о пользователе Яндекса.
Токен должен быть передан в заголовке 'Authorization: Bearer <token>'.
"""
token = credentials.credentials
headers = {'Authorization': f'OAuth {token}'}
try:
async with httpx.AsyncClient() as client:
response = await client.get(YANDEX_USERINFO_URL, headers=headers)
response.raise_for_status()
user_data = response.json()
logger.info(f"Fetched user info for login: {user_data.get('login')}")
return UserInfoResponse(**user_data)
except httpx.HTTPStatusError as e:
error_details = e.response.json()
logger.error(f"Yandex UserInfo API error: {e.response.status_code} - {error_details}")
raise HTTPException(
status_code=e.response.status_code,
detail=f"Yandex API Error: {error_details.get('error_description', 'Unknown error')}"
)
except Exception:
logger.opt(exception=True).error("An unexpected error occurred while fetching user info.")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="An internal server error occurred."
)