DRF, allauth и dj-rest-auth - аутентификация с неактивными пользователями возвращает None вместо объекта пользователя - PullRequest
0 голосов
/ 10 июля 2020

Я использую all-auth и dj-rest-auth для регистрации и входа по электронной почте. Все работает нормально, но при выполнении теста неактивные пользователи возвращают сообщение с неверными учетными данными вместо сообщения неактивной учетной записи. В LoginSerializer кажется, что метод аутентификации django .contrib.auth не возвращает пользователя, но None. Вот код:

settings.py

AUTHENTICATION_BACKENDS = [
   "django.contrib.auth.backends.AllowAllUsersModelBackend",
   "allauth.account.auth_backends.AuthenticationBackend"
]

REST_AUTH_REGISTER_SERIALIZERS = {
    'REGISTER_SERIALIZER': 'user.serializers.RegisterSerializer',
}

REST_AUTH_SERIALIZERS = {
    'LOGIN_SERIALIZER': 'user.serializers.LoginSerializer',
    'USER_DETAILS_SERIALIZER': 'user.serializers.UserDetailSerializer',
}

serializers.py

class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True, allow_blank=False)
    password = serializers.CharField(style={'input_type': 'password'})

    def authenticate(self, **kwargs):
        return authenticate(self.context['request'], **kwargs)

    def _validate_email(self, email, password):
        user = None
        if email and password:
            user = self.authenticate(email=email, password=password)
        else:
            msg = _('Must include "email" and "password".')
            raise exceptions.ValidationError(msg)

        return user

    def validate(self, attrs):
        email = attrs.get('email')
        password = attrs.get('password')

        user = None
        if 'allauth' in settings.INSTALLED_APPS:
            from allauth.account import app_settings
            # Authentication through email
            if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.EMAIL:
                user = self._validate_email(email, password)

        # Did we get back an inactive user?
        if user:
            if not user.is_active:
                msg = _('User account is disabled.')
                raise exceptions.ValidationError(msg)
        else:
            msg = _('Unable to log in with provided credentials.')
            raise exceptions.ValidationError(msg)

        # If required, is the email verified?
        if 'dj_rest_auth.registration' in settings.INSTALLED_APPS:
            from allauth.account import app_settings
            if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
                try:
                    email_address = user.emailaddress_set.get(email=user.email)
                except:
                    raise serializers.ValidationError(_('E-mail is not registered.'))
                else:
                    if not email_address.verified:
                        raise serializers.ValidationError(_('E-mail is not verified.'))


        attrs['user'] = user
        return attrs

tests.py

########################################################################
# LOG IN WITH INACTIVE USER
login_data = {
    'email': 'inactive@inactive.com',
    'password': '9I8u7Y6t5R4e'
}
response = self.client.post('http://localhost:8000/api/auth/login/', login_data)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
expected_error = {
    'non_field_errors': 'User account is disabled.'
}
response_error = {
    'non_field_errors': response.data['non_field_errors'][0]
}
self.assertEqual(response_error, expected_error)

Что-то мне не хватает?

Заранее спасибо.

1 Ответ

1 голос
/ 11 июля 2020

В случае, если кому-то интересно, я обнаружил проблему: бэкэнд аутентификации allauth переопределяет бэкэнд модели django. Чтобы решить эту проблему, я создаю класс, унаследованный от бэкэнда allauth, и добавляю функцию, которая позволяет всем пользователям входить в систему:

backend.py

from allauth.account.auth_backends import AuthenticationBackend

class AllowAllUsersModelBackend(AuthenticationBackend):

    def user_can_authenticate(self, user):
        return True

Затем добавьте в настройки:

settings.py

AUTHENTICATION_BACKENDS = [
   "user.backends.AllowAllUsersModelBackend",
]
...