DRF,allauth和dj-rest-auth-使用不活动的用户进行身份验证将返回None而不是用户对象

时间:2020-07-10 07:25:41

标签: django django-rest-framework django-allauth django-rest-auth

我正在使用all-auth和dj-rest-auth来实现通过电子邮件的注册和登录。一切正常,但进行测试时,不活动的用户将返回无效的凭据消息,而不是不活动的帐户消息。在LoginSerializer中,似乎django.contrib.auth authenticate方法不会返回用户,但不会返回用户。这是代码:

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 个答案:

答案 0 :(得分:1)

如果有人感兴趣,我发现了问题:allauth身份验证后端将覆盖django模型后端。为了解决这个问题,我创建了一个从allauth后端继承的类,并添加了允许所有用户登录的函数:

backend.py

setState()

然后将其添加到设置:

settings.py

from allauth.account.auth_backends import AuthenticationBackend

class AllowAllUsersModelBackend(AuthenticationBackend):

    def user_can_authenticate(self, user):
        return True