172 lines
6.7 KiB
Python
172 lines
6.7 KiB
Python
from rest_framework import status
|
||
from rest_framework.decorators import action
|
||
from rest_framework.response import Response
|
||
from rest_framework_simplejwt.tokens import RefreshToken
|
||
from rest_framework.views import APIView
|
||
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample
|
||
from drf_spectacular.types import OpenApiTypes
|
||
|
||
from django.contrib.auth.models import User
|
||
|
||
from .serializers import (
|
||
UserResponseSerializer,
|
||
LoginRequestSerializer,
|
||
LoginResponseSerializer,
|
||
LogoutResponseSerializer
|
||
)
|
||
|
||
from api.utils.cookies import AuthBaseViewSet
|
||
from api.types import User
|
||
|
||
|
||
class LoginViewSet(AuthBaseViewSet):
|
||
"""ViewSet для авторизации пользователей"""
|
||
serializer_class = LoginRequestSerializer
|
||
|
||
@extend_schema(
|
||
summary="Авторизация пользователя",
|
||
description="Эндпоинт для авторизации пользователя по логину и паролю",
|
||
responses={
|
||
200: OpenApiResponse(
|
||
response=LoginResponseSerializer,
|
||
description="Успешная авторизация",
|
||
examples=[
|
||
OpenApiExample(
|
||
'Успешный ответ',
|
||
value={
|
||
"message": "Успешная авторизация",
|
||
"access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
|
||
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
|
||
"user": {
|
||
"id": 1,
|
||
"email": "user@example.com",
|
||
"account_type": "engieneer",
|
||
"name": "Иван",
|
||
"surname": "Иванов",
|
||
"imageURL": "https://example.com/avatar.jpg",
|
||
"uuid": "abc123"
|
||
}
|
||
}
|
||
)
|
||
]
|
||
),
|
||
400: OpenApiResponse(
|
||
description="Неверные параметры запроса",
|
||
response=OpenApiTypes.OBJECT,
|
||
examples=[
|
||
OpenApiExample(
|
||
'Отсутствуют обязательные поля',
|
||
value={"error": "Логин и пароль обязательны"}
|
||
)
|
||
]
|
||
),
|
||
403: OpenApiResponse(
|
||
description="Неверный пароль",
|
||
response=OpenApiTypes.OBJECT,
|
||
examples=[
|
||
OpenApiExample(
|
||
'Неверный пароль',
|
||
value={"error": "Неверный пароль"}
|
||
)
|
||
]
|
||
),
|
||
404: OpenApiResponse(
|
||
description="Пользователь не найден",
|
||
response=OpenApiTypes.OBJECT,
|
||
examples=[
|
||
OpenApiExample(
|
||
'Пользователь не найден',
|
||
value={"error": "Пользователь не найден"}
|
||
)
|
||
]
|
||
),
|
||
500: OpenApiResponse(
|
||
description="Внутренняя ошибка сервера",
|
||
response=OpenApiTypes.OBJECT,
|
||
examples=[
|
||
OpenApiExample(
|
||
'Ошибка сервера',
|
||
value={"error": "Ошибка авторизации"}
|
||
)
|
||
]
|
||
)
|
||
}
|
||
)
|
||
@action(detail=False, methods=['post'], url_path="login")
|
||
def login_client(self, request):
|
||
try:
|
||
login = request.data.get("login")
|
||
password = request.data.get("password")
|
||
|
||
if not login or not password:
|
||
return Response(
|
||
{"error": "Логин и пароль обязательны"},
|
||
status=status.HTTP_400_BAD_REQUEST
|
||
)
|
||
|
||
try:
|
||
user = User.objects.get(login=login)
|
||
except User.DoesNotExist:
|
||
return Response(
|
||
{"error": "Пользователь не найден"},
|
||
status=status.HTTP_404_NOT_FOUND
|
||
)
|
||
if not user.check_password(password):
|
||
return Response(
|
||
{"error": "Неверный пароль"},
|
||
status=status.HTTP_403_FORBIDDEN
|
||
)
|
||
|
||
refresh = RefreshToken.for_user(user)
|
||
|
||
user_data = UserResponseSerializer(user).data
|
||
|
||
response = Response({
|
||
"message": "Успешная авторизация",
|
||
"access": str(refresh.access_token),
|
||
"refresh": str(refresh),
|
||
"user": user_data
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
# сеттим куки
|
||
return self._set_auth_cookies(response, refresh)
|
||
|
||
except Exception as e:
|
||
return Response(
|
||
{"error": "Ошибка авторизации"},
|
||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||
)
|
||
|
||
class LogoutView(APIView):
|
||
"""View для выхода из системы"""
|
||
serializer_class = LogoutResponseSerializer
|
||
|
||
@extend_schema(
|
||
summary="Выход из системы",
|
||
description="Эндпоинт для выхода из системы. Очищает JWT токены и сессионные куки.",
|
||
responses={
|
||
200: OpenApiResponse(
|
||
response=LogoutResponseSerializer,
|
||
description="Успешный выход из системы",
|
||
examples=[
|
||
OpenApiExample(
|
||
'Успешный выход',
|
||
value={"message": "Успешный выход из системы"}
|
||
)
|
||
]
|
||
)
|
||
},
|
||
tags=['Аутентификация']
|
||
)
|
||
def post(self, request):
|
||
"""Выход из системы с очисткой всех токенов и куки"""
|
||
response = Response(
|
||
{'message': 'Успешный выход из системы'},
|
||
status=status.HTTP_200_OK
|
||
)
|
||
|
||
response.delete_cookie('access_token')
|
||
response.delete_cookie('refresh_token')
|
||
response.delete_cookie('sessionid')
|
||
|
||
return response |