refresh token route

This commit is contained in:
Timofey
2025-08-29 15:13:15 +03:00
parent 9228a38511
commit 752afd372b
4 changed files with 118 additions and 5 deletions

View File

@@ -1,4 +1,7 @@
from rest_framework import status
from datetime import datetime
import traceback
from django.conf import settings
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
@@ -12,13 +15,16 @@ from .serializers import (
UserResponseSerializer,
LoginRequestSerializer,
LoginResponseSerializer,
LogoutResponseSerializer
LogoutResponseSerializer,
RefreshTokenRequestSerializer,
RefreshTokenResponseSerializer
)
from api.utils.cookies import AuthBaseViewSet
from api.types import User
@extend_schema(tags=['Логин'])
class LoginViewSet(AuthBaseViewSet):
"""ViewSet для авторизации пользователей"""
serializer_class = LoginRequestSerializer
@@ -136,7 +142,89 @@ class LoginViewSet(AuthBaseViewSet):
{"error": "Ошибка авторизации"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
@extend_schema(tags=['Логин'])
class RefreshTokenView(APIView):
"""View для обновления JWT токенов"""
serializer_class = RefreshTokenRequestSerializer
@extend_schema(
summary="Обновление токенов",
description="Эндпоинт для обновления JWT токенов. Принимает refresh token и возвращает новую пару токенов.",
request=RefreshTokenRequestSerializer,
responses={
200: OpenApiResponse(
response=RefreshTokenResponseSerializer,
description="Токены успешно обновлены",
examples=[
OpenApiExample(
'Успешное обновление',
value={
"access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"expires_at": 1679831642.0
}
)
]
),
400: OpenApiResponse(
description="Ошибка обновления токена",
response=OpenApiTypes.OBJECT,
examples=[
OpenApiExample(
'Отсутствует refresh token',
value={"error": "Refresh token is required"}
),
OpenApiExample(
'Невалидный refresh token',
value={"error": "Invalid refresh token: Token is invalid or expired"}
)
]
)
}
)
def post(self, request):
try:
refresh_token = request.data.get('refresh')
if not refresh_token:
return Response(
{'error': 'Требуется refresh token'},
status=status.HTTP_400_BAD_REQUEST
)
try:
token = RefreshToken(refresh_token)
# точное время истечения токена
expires_at = datetime.now() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME']
response_data = {
'access': str(token.access_token),
'refresh': str(token),
'expires_at': datetime.timestamp(expires_at)
}
return Response(response_data)
except Exception as e:
# логируем ошибки
print(f"Token refresh error: {str(e)}")
print(traceback.format_exc())
return Response(
{'error': f'Невалидный refresh token: {str(e)}'},
status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
return Response(
{'error': f'Ошибка обновления токена: {str(e)}'},
status=status.HTTP_400_BAD_REQUEST
)
@extend_schema(tags=['Логаут'])
class LogoutView(APIView):
"""View для выхода из системы"""
serializer_class = LogoutResponseSerializer
@@ -155,8 +243,7 @@ class LogoutView(APIView):
)
]
)
},
tags=['Аутентификация']
}
)
def post(self, request):
"""Выход из системы с очисткой всех токенов и куки"""