简体   繁体   English

Django 使用带有 djoser 的电子邮件身份验证进行登录

[英]Django using email authentication with djoser for login

So i tried using djoser recently and i want to use email instead of username to login.所以我最近尝试使用 djoser,我想使用电子邮件而不是用户名登录。

Djoser : http://djoser.readthedocs.io/en/latest/index.html乔瑟: http : //djoser.readthedocs.io/en/latest/index.html

Then i try to customise the token create/login to change from username to email in the serializers.py然后我尝试自定义令牌创建/登录以在 serializers.py 中从用户名更改为电子邮件

Original原来的

class TokenCreateSerializer(serializers.Serializer):
password = serializers.CharField(
    required=False, style={'input_type': 'password'}
    )

    default_error_messages = {
        'invalid_credentials': constants.INVALID_CREDENTIALS_ERROR,
        'inactive_account': constants.INACTIVE_ACCOUNT_ERROR,
    }

    def __init__(self, *args, **kwargs):
        super(TokenCreateSerializer, self).__init__(*args, **kwargs)
    self.user = None
    self.fields[User.USERNAME_FIELD] = serializers.CharField(
        required=False
    )

def validate(self, attrs):
    self.user = authenticate(
        username=attrs.get(User.USERNAME_FIELD),
        password=attrs.get('password')
        )

        self._validate_user_exists(self.user)
        self._validate_user_is_active(self.user)
        return attrs

    def _validate_user_exists(self, user):
        if not user:
            self.fail('invalid_credentials')

    def _validate_user_is_active(self, user):
        if not user.is_active:
            self.fail('inactive_account')

Edited已编辑

class TokenCreateSerializer(serializers.Serializer):
password = serializers.CharField(
    required=False, style={'input_type': 'password'}
    )

    default_error_messages = {
        'invalid_credentials': constants.INVALID_CREDENTIALS_ERROR,
        'inactive_account': constants.INACTIVE_ACCOUNT_ERROR,
    }

    def __init__(self, *args, **kwargs):
        super(TokenCreateSerializer, self).__init__(*args, **kwargs)
    self.user = None
    self.fields[User.EMAIL_FIELD] = serializers.EmailField(
        required=False
    )

def validate(self, attrs):
    self.user = authenticate(
        email=attrs.get(User.EMAIL_FIELD),
        password=attrs.get('password')
        )

        self._validate_user_exists(self.user)
        self._validate_user_is_active(self.user)
        return attrs

    def _validate_user_exists(self, user):
        if not user:
            self.fail('invalid_credentials')

    def _validate_user_is_active(self, user):
        if not user.is_active:
            self.fail('inactive_account')

but the result i get in the api is this但我在 api 中得到的结果是这样的

{
"non_field_errors": [
    "Unable to login with provided credentials."
]

I did try other method but all have same result.我确实尝试过其他方法,但结果都相同。 Is there a way to make it using of email to authenticate instead of username ?有没有办法让它使用电子邮件而不是用户名进行身份验证?

Djoser uses authenticate method from django.contrib.auth . Djoser使用来自django.contrib.auth authenticate方法。 By default the AUTHENTICATION_BACKENDS is set to use django.contrib.auth.backends.ModelBackend which will try to get the user model using default manager get_by_natural_key method, which does:默认情况下, AUTHENTICATION_BACKENDS设置为使用django.contrib.auth.backends.ModelBackend它将尝试使用默认管理器get_by_natural_key方法获取用户模型,它执行:

def get_by_natural_key(self, username):
    return self.get(**{self.model.USERNAME_FIELD: username})

You can check the source code for this.您可以为此检查源代码

My approach on this was to enhance django's UserManager , assuming your User model is subclass of AbstractUser , by trying to get the user by email or username, like this:我对此的方法是增强 django 的UserManager ,假设您的User模型是AbstractUser子类,通过尝试通过电子邮件或用户名获取用户,如下所示:

from django.contrib.auth.models import UserManager
from django.db.models import Q

class CustomUserManager(UserManager):

    def get_by_natural_key(self, username):
        return self.get(
            Q(**{self.model.USERNAME_FIELD: username}) |
            Q(**{self.model.EMAIL_FIELD: username})
        )

Use that in your User model在您的User模型中使用它

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    ...
    objects = CustomUserManager()

You should now be able to login using email or username您现在应该可以使用电子邮件或用户名登录

I was looking for the answer to this question and came across this thread!我正在寻找这个问题的答案并遇到了这个线程!

Everything works, but then I found an even simpler solution:一切正常,但后来我找到了一个更简单的解决方案:

DJOSER = {
    'LOGIN_FIELD': 'email'
}

I don't know, maybe someone will need it!我不知道,也许有人会需要它!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM