Проверка, активна ли учетная запись пользователя в Django Rest Framework

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

Я пытаюсь реализовать активацию учетной записи по ссылке электронной почты. Моя User модель очень проста, наследуется от django.contrib.auth.models.AbstractUser , поэтому по умолчанию в ней есть is_active поле. После регистрации создается новый пользователь с is_active=False параметром, и я хочу обработать случай, когда пользователь пытается войти в систему, и даже если учетные данные в порядке, не следует входить в систему, потому что учетная запись не активирована. Я использую аутентификацию токеном Knox. Мой сериализатор:

 from django.contrib.auth import authenticate
from rest_framework import serializers, exceptions


class LoginUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserModel
        fields = ('username', 'password')

    def validate(self, data):
        user = authenticate(**data)
        if user:
            if user.is_active:
                return user
            raise exceptions.AuthenticationFailed('Account is not activated')
        raise exceptions.AuthenticationFailed()
  

И просмотрите:

 from django.contrib.auth import login
from rest_framework.permissions import AllowAny
from rest_framework.authtoken.serializers import AuthTokenSerializer
from knox.views import LoginView
from .serializers import LoginUserSerializer


class LoginUserView(LoginView):
    serializer_class = LoginUserSerializer
    permission_classes = [AllowAny]

    def post(self, request, *args, **kwargs):
        serializer = AuthTokenSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        return super(LoginUserView, self).post(request)
  

И с этим кодом я наткнулся на проблему: когда я пытаюсь войти в систему с уже активированной учетной записью, все выглядит нормально, но когда я пытаюсь использовать неактивированную, вместо Account is not activated я получаю:

 {
    "non_field_errors": [
        "Unable to log in with provided credentials."
    ]
}
  

Я думаю, это происходит скорее из view, чем из сериализатора.

Комментарии:

1. Django не может не авторизовать неактивную учетную запись. Вот почему вы получаете эту ошибку

2. Вы правы, спасибо! Я добавил AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.AllowAllUsersModelBackend'] в settings.py , и теперь я могу войти в систему с неактивной учетной записью. Но теперь я столкнулся с другой проблемой — это каким-то образом пропускает проверки в validate() в serializer, что означает, что даже если учетная запись неактивна, но вошла в систему, она проходит user.is_active проверку, и исключения, определенные мной, вообще не создаются (в обоих случаях, если пользователь и если ошибка user.is_active). Что еще более странно, я заменил исключения на return status.HTTP_401_UNAUTHORIZED и по-прежнему ничего.

3. Попробуйте выполнить отладку. Достигнут ли ваш запрос на данный момент user = authenticate(**data) ?

Ответ №1:

Итак, благодаря предложению Шафикура Рахмана я смог заставить это работать. После того, как я попытался отладить это с помощью pdb и установить trace внутри LoginUserSerializer , но ничего не произошло, я понял, что в своих представлениях я указываю не на сериализатор, который я написал, а на AuthTokenSerializer . Даже после этого это все еще не сработало из-за моего непонимания того, как работают django login() и DRF validate() . Ниже исправлен код для справки:

Вид:

 class LoginUserView(LoginView):
    serializer_class = LoginUserSerializer
    permission_classes = [AllowAny]

    def post(self, request, *args, **kwargs):
        serializer = LoginUserSerializer(data=request.data)  # changed  to desired serializer
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        return super(LoginUserView, self).post(request)
  

и сериализатор:

 class LoginUserSerializer(serializers.ModelSerializer):
    username = serializers.CharField()  # added missing fields for serializer
    password = serializers.CharField()

    class Meta:
        model = UserModel
        fields = ('username', 'password')

    def validate(self, data):
        user = authenticate(**data)
        if user:
            if user.is_active:
                data['user'] = user  # added user model to OrderedDict that serializer is validating
                return data  # and in sunny day scenario, return this dict, as everything is fine
            raise exceptions.AuthenticationFailed('Account is not activated')
        raise exceptions.AuthenticationFailed()
  

Кроме того, чтобы иметь возможность authenticate() неактивному пользователю, мне пришлось добавить

 AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.AllowAllUsersModelBackend'
]
  

в настройках проекта.