97 lines
3.1 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 __future__ import annotations
import logging
import time
from drf_spectacular.utils import (
OpenApiExample,
OpenApiResponse,
extend_schema,
)
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from ..serializers import (
PhoneOrEmailTokenObtainPairSerializer,
SessionTokenRefreshSerializer,
TokenPairResponseSerializer,
TokenRefreshRequestSerializer,
TokenRefreshResponseSerializer,
)
from ..services import (
extract_client_ip,
)
logger = logging.getLogger(__name__)
@extend_schema(
tags=["Auth"],
summary="Получить JWT access и refresh токены",
description=(
"Принимает email или телефон вместе с паролем. "
"Если передан телефон, backend найдёт пользователя "
"и использует его email "
"для стандартной JWT-аутентификации."
),
request=PhoneOrEmailTokenObtainPairSerializer,
responses={
200: TokenPairResponseSerializer,
401: OpenApiResponse(
description=(
"Неверные учетные данные или email пользователя не подтвержден."
),
),
},
examples=[
OpenApiExample(
"Вход по email",
value={"email": "user@example.com", "password": "Str0ngPass!"},
request_only=True,
),
OpenApiExample(
"Вход по телефону",
value={"phone_number": "+79990000001", "password": "Str0ngPass!"},
request_only=True,
),
],
)
class PhoneOrEmailTokenObtainPairView(TokenObtainPairView):
serializer_class = PhoneOrEmailTokenObtainPairSerializer
throttle_scope = "auth_login"
@extend_schema(
tags=["Auth"],
summary="Обновить JWT access token",
description="Принимает refresh token и возвращает новый access token.",
request=TokenRefreshRequestSerializer,
responses={
200: TokenRefreshResponseSerializer,
401: OpenApiResponse(
description="Refresh token недействителен, истек или сессия отозвана."
),
},
)
class JWTTokenRefreshView(TokenRefreshView):
serializer_class = SessionTokenRefreshSerializer
throttle_scope = "auth_refresh"
def initial(self, request, *args, **kwargs):
self._refresh_started_at = time.monotonic()
return super().initial(request, *args, **kwargs)
def finalize_response(self, request, response, *args, **kwargs):
duration_ms = round(
(time.monotonic() - getattr(self, "_refresh_started_at", time.monotonic()))
* 1000,
1,
)
log = logger.info if response.status_code < 400 else logger.warning
log(
"JWT refresh completed status=%s duration_ms=%s ip=%s",
response.status_code,
duration_ms,
extract_client_ip(request),
)
return super().finalize_response(request, response, *args, **kwargs)