auth fixes, search connected
This commit is contained in:
@@ -376,16 +376,13 @@ def login_accepted(func):
|
||||
try:
|
||||
author = session.query(Author).filter(Author.id == auth.author_id).one()
|
||||
info.context["author"] = author.dict()
|
||||
info.context["user_id"] = author.id
|
||||
logger.debug(f"[login_accepted] Пользователь авторизован: {author.id}")
|
||||
except exc.NoResultFound:
|
||||
logger.warning(f"[login_accepted] Пользователь с ID {auth.author_id} не найден в базе данных")
|
||||
info.context["author"] = None
|
||||
info.context["user_id"] = None
|
||||
else:
|
||||
# Если пользователь не авторизован, устанавливаем пустые значения
|
||||
info.context["author"] = None
|
||||
info.context["user_id"] = None
|
||||
logger.debug("[login_accepted] Пользователь не авторизован")
|
||||
|
||||
return await func(parent, info, *args, **kwargs)
|
||||
|
54
auth/handler.py
Normal file
54
auth/handler.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from ariadne.asgi.handlers import GraphQLHTTPHandler
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response, JSONResponse
|
||||
from auth.middleware import auth_middleware
|
||||
from utils.logger import root_logger as logger
|
||||
|
||||
class EnhancedGraphQLHTTPHandler(GraphQLHTTPHandler):
|
||||
"""
|
||||
Улучшенный GraphQL HTTP обработчик с поддержкой cookie и авторизации.
|
||||
|
||||
Расширяет стандартный GraphQLHTTPHandler для:
|
||||
1. Создания расширенного контекста запроса с авторизационными данными
|
||||
2. Корректной обработки ответов с cookie и headers
|
||||
3. Интеграции с AuthMiddleware
|
||||
"""
|
||||
|
||||
async def get_context_for_request(self, request: Request, data: dict) -> dict:
|
||||
"""
|
||||
Расширяем контекст для GraphQL запросов.
|
||||
|
||||
Добавляет к стандартному контексту:
|
||||
- Объект response для установки cookie
|
||||
- Интеграцию с AuthMiddleware
|
||||
- Расширения для управления авторизацией
|
||||
|
||||
Args:
|
||||
request: Starlette Request объект
|
||||
data: данные запроса
|
||||
|
||||
Returns:
|
||||
dict: контекст с дополнительными данными для авторизации и cookie
|
||||
"""
|
||||
# Получаем стандартный контекст от базового класса
|
||||
context = await super().get_context_for_request(request, data)
|
||||
|
||||
# Создаем объект ответа для установки cookie
|
||||
response = JSONResponse({})
|
||||
context["response"] = response
|
||||
|
||||
# Интегрируем с AuthMiddleware
|
||||
auth_middleware.set_context(context)
|
||||
context["extensions"] = auth_middleware
|
||||
|
||||
# Добавляем данные авторизации только если они доступны
|
||||
# Без проверки hasattr, так как это вызывает ошибку до обработки AuthenticationMiddleware
|
||||
if hasattr(request, "auth") and request.auth:
|
||||
# Используем request.auth вместо request.user, так как user еще не доступен
|
||||
context["auth"] = request.auth
|
||||
# Безопасно логируем информацию о типе объекта auth
|
||||
logger.debug(f"[graphql] Добавлены данные авторизации в контекст: {type(request.auth).__name__}")
|
||||
|
||||
logger.debug(f"[graphql] Подготовлен расширенный контекст для запроса")
|
||||
|
||||
return context
|
@@ -1,11 +1,13 @@
|
||||
"""
|
||||
Middleware для обработки авторизации в GraphQL запросах
|
||||
"""
|
||||
|
||||
from typing import Any, Dict
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse, Response
|
||||
from starlette.datastructures import Headers
|
||||
from starlette.types import ASGIApp, Scope, Receive, Send
|
||||
from utils.logger import root_logger as logger
|
||||
from settings import SESSION_TOKEN_HEADER, SESSION_COOKIE_NAME
|
||||
from settings import SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_MAX_AGE, SESSION_COOKIE_SAMESITE, SESSION_COOKIE_SECURE, SESSION_TOKEN_HEADER, SESSION_COOKIE_NAME
|
||||
|
||||
|
||||
class AuthMiddleware:
|
||||
@@ -197,3 +199,76 @@ class AuthMiddleware:
|
||||
except Exception as e:
|
||||
logger.error(f"[AuthMiddleware] Ошибка в GraphQL resolve: {str(e)}")
|
||||
raise
|
||||
|
||||
async def process_result(self, request: Request, result: Any) -> Response:
|
||||
"""
|
||||
Обрабатывает результат GraphQL запроса, поддерживая установку cookie
|
||||
|
||||
Args:
|
||||
request: Starlette Request объект
|
||||
result: результат GraphQL запроса (dict или Response)
|
||||
|
||||
Returns:
|
||||
Response: HTTP-ответ с результатом и cookie (если необходимо)
|
||||
"""
|
||||
|
||||
# Проверяем, является ли result уже объектом Response
|
||||
if isinstance(result, Response):
|
||||
response = result
|
||||
# Пытаемся получить данные из response для проверки логина/логаута
|
||||
result_data = {}
|
||||
if isinstance(result, JSONResponse):
|
||||
try:
|
||||
import json
|
||||
result_data = json.loads(result.body.decode('utf-8'))
|
||||
except Exception as e:
|
||||
logger.error(f"[process_result] Не удалось извлечь данные из JSONResponse: {str(e)}")
|
||||
else:
|
||||
response = JSONResponse(result)
|
||||
result_data = result
|
||||
|
||||
# Проверяем, был ли токен в запросе или ответе
|
||||
if request.method == "POST":
|
||||
try:
|
||||
data = await request.json()
|
||||
op_name = data.get("operationName", "").lower()
|
||||
|
||||
# Если это операция логина или обновления токена, и в ответе есть токен
|
||||
if op_name in ["login", "refreshtoken"]:
|
||||
token = None
|
||||
# Пытаемся извлечь токен из данных ответа
|
||||
if result_data and isinstance(result_data, dict):
|
||||
data_obj = result_data.get("data", {})
|
||||
if isinstance(data_obj, dict) and op_name in data_obj:
|
||||
op_result = data_obj.get(op_name, {})
|
||||
if isinstance(op_result, dict) and "token" in op_result:
|
||||
token = op_result.get("token")
|
||||
|
||||
if token:
|
||||
# Устанавливаем cookie с токеном
|
||||
response.set_cookie(
|
||||
key=SESSION_COOKIE_NAME,
|
||||
value=token,
|
||||
httponly=SESSION_COOKIE_HTTPONLY,
|
||||
secure=SESSION_COOKIE_SECURE,
|
||||
samesite=SESSION_COOKIE_SAMESITE,
|
||||
max_age=SESSION_COOKIE_MAX_AGE,
|
||||
)
|
||||
logger.debug(f"[graphql_handler] Установлена cookie {SESSION_COOKIE_NAME} для операции {op_name}")
|
||||
|
||||
# Если это операция logout, удаляем cookie
|
||||
elif op_name == "logout":
|
||||
response.delete_cookie(
|
||||
key=SESSION_COOKIE_NAME,
|
||||
secure=SESSION_COOKIE_SECURE,
|
||||
httponly=SESSION_COOKIE_HTTPONLY,
|
||||
samesite=SESSION_COOKIE_SAMESITE
|
||||
)
|
||||
logger.debug(f"[graphql_handler] Удалена cookie {SESSION_COOKIE_NAME} для операции {op_name}")
|
||||
except Exception as e:
|
||||
logger.error(f"[process_result] Ошибка при обработке POST запроса: {str(e)}")
|
||||
|
||||
return response
|
||||
|
||||
# Создаем единый экземпляр AuthMiddleware для использования с GraphQL
|
||||
auth_middleware = AuthMiddleware(lambda scope, receive, send: None)
|
Reference in New Issue
Block a user