session-mdlwr-oauth-fix
All checks were successful
Deploy on push / deploy (push) Successful in 7m9s

This commit is contained in:
2025-09-23 18:54:56 +03:00
parent 71b47bfe59
commit e0f3272bed

View File

@@ -467,7 +467,7 @@ async def oauth_callback(request: Any) -> JSONResponse | RedirectResponse:
else None, else None,
device_info={ device_info={
"user_agent": request.headers.get("user-agent"), "user_agent": request.headers.get("user-agent"),
"ip": request.client.host if hasattr(request, "client") else None, "ip": request.client.host if hasattr(request, "client") and request.client else None,
}, },
) )
@@ -536,12 +536,7 @@ async def oauth_login_http(request: Request) -> JSONResponse | RedirectResponse:
code_challenge = create_s256_code_challenge(code_verifier) code_challenge = create_s256_code_challenge(code_verifier)
state = token_urlsafe(32) state = token_urlsafe(32)
# Сохраняем состояние в сессии # 🔍 Сохраняем состояние OAuth только в Redis (убираем зависимость от request.session)
request.session["code_verifier"] = code_verifier
request.session["provider"] = provider
request.session["state"] = state
# Сохраняем состояние OAuth в Redis
oauth_data = { oauth_data = {
"code_verifier": code_verifier, "code_verifier": code_verifier,
"provider": provider, "provider": provider,
@@ -569,24 +564,27 @@ async def oauth_login_http(request: Request) -> JSONResponse | RedirectResponse:
async def oauth_callback_http(request: Request) -> JSONResponse | RedirectResponse: async def oauth_callback_http(request: Request) -> JSONResponse | RedirectResponse:
"""HTTP handler для OAuth callback""" """HTTP handler для OAuth callback"""
try: try:
# Используем GraphQL resolver логику # 🔍 Получаем состояние OAuth только из Redis (убираем зависимость от request.session)
provider = request.session.get("provider")
if not provider:
return JSONResponse({"error": "No OAuth session found"}, status_code=400)
state = request.query_params.get("state") state = request.query_params.get("state")
session_state = request.session.get("state") if not state:
return JSONResponse({"error": "Missing OAuth state parameter"}, status_code=400)
if not state or state != session_state:
return JSONResponse({"error": "Invalid or expired OAuth state"}, status_code=400)
oauth_data = await get_oauth_state(state) oauth_data = await get_oauth_state(state)
if not oauth_data: if not oauth_data:
return JSONResponse({"error": "Invalid or expired OAuth state"}, status_code=400) return JSONResponse({"error": "Invalid or expired OAuth state"}, status_code=400)
provider = oauth_data.get("provider")
if not provider:
return JSONResponse({"error": "No provider in OAuth state"}, status_code=400)
# Используем существующую логику # Используем существующую логику
client = oauth.create_client(provider) client = oauth.create_client(provider)
if not client:
return JSONResponse({"error": "Provider not configured"}, status_code=400)
token = await client.authorize_access_token(request) token = await client.authorize_access_token(request)
if not token:
return JSONResponse({"error": "Failed to get access token"}, status_code=400)
profile = await get_user_profile(provider, client, token) profile = await get_user_profile(provider, client, token)
if not profile: if not profile:
@@ -594,17 +592,34 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon
# Создаем или обновляем пользователя используя helper функцию # Создаем или обновляем пользователя используя helper функцию
author = await _create_or_update_user(provider, profile) author = await _create_or_update_user(provider, profile)
if not author:
return JSONResponse({"error": "Failed to create/update user"}, status_code=500)
# Создаем токен сессии # Создаем токен сессии с полными данными
session_token = await TokenStorage.create_session(str(author.id)) session_token = await TokenStorage.create_session(
str(author.id),
auth_data={
"provider": provider,
"profile": profile,
},
username=author.name
if isinstance(author.name, str)
else str(author.name)
if author.name is not None
else None,
device_info={
"user_agent": request.headers.get("user-agent"),
"ip": request.client.host if hasattr(request, "client") and request.client else None,
},
)
# Очищаем OAuth сессию # Получаем redirect_uri из OAuth данных
request.session.pop("code_verifier", None) redirect_uri = oauth_data.get("redirect_uri", FRONTEND_URL)
request.session.pop("provider", None) if not isinstance(redirect_uri, str) or not redirect_uri:
request.session.pop("state", None) redirect_uri = FRONTEND_URL
# Возвращаем redirect с cookie # Возвращаем redirect с cookie
response = RedirectResponse(url="/auth/success", status_code=307) response = RedirectResponse(url=str(redirect_uri), status_code=307)
response.set_cookie( response.set_cookie(
SESSION_COOKIE_NAME, SESSION_COOKIE_NAME,
session_token, session_token,
@@ -612,12 +627,17 @@ async def oauth_callback_http(request: Request) -> JSONResponse | RedirectRespon
secure=SESSION_COOKIE_SECURE, secure=SESSION_COOKIE_SECURE,
samesite=SESSION_COOKIE_SAMESITE, samesite=SESSION_COOKIE_SAMESITE,
max_age=SESSION_COOKIE_MAX_AGE, max_age=SESSION_COOKIE_MAX_AGE,
path="/", # Важно: устанавливаем path="/" для доступности cookie во всех путях
) )
logger.info(f"OAuth успешно завершен для {provider}, user_id={author.id}")
return response return response
except Exception as e: except Exception as e:
logger.error(f"OAuth callback error: {e}") logger.error(f"OAuth callback error: {e!s}")
return JSONResponse({"error": "OAuth callback failed"}, status_code=500) # В случае ошибки редиректим на фронтенд с ошибкой
fallback_redirect = request.query_params.get("redirect_uri", FRONTEND_URL)
return RedirectResponse(url=f"{fallback_redirect}?error=auth_failed")
async def _create_or_update_user(provider: str, profile: dict) -> Author: async def _create_or_update_user(provider: str, profile: dict) -> Author: