如何修改LoginSerializer的一个字段用于用户名/电话/电子邮件?

7
在自定义的LoginSerializer中:
class LoginSerializer(serializers.Serializer):
    username = serializers.CharField(required=False, allow_blank=True)
    email = serializers.EmailField(required=False, allow_blank=True)
    password = serializers.CharField(style={'input_type': 'password'})

    def _validate_email(self, email, password):
        user = None

        if email and password:
            user = authenticate(email=email, password=password)
        else:
            msg = 'must input email and password'
            raise exceptions.ValidationError(msg)

        return user

    def _validate_username(self, username, password):
        user = None

        if username and password:
            user = authenticate(username=username, password=password)
        else:
            msg = 'must input username and password'
            raise exceptions.ValidationError(msg)

        return user

    def _validate_username_email(self, username, email, password):
        user = None

        if email and password:
            user = authenticate(email=email, password=password)
        elif username and password:
            user = authenticate(username=username, password=password)
        else:
            msg = 'must type in email and pwd or username and pwd'
            raise exceptions.ValidationError(msg)

        return user

    def validate(self, attrs):
        username = attrs.get('username')
        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)

            # Authentication through username
            if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME:
                user = self._validate_username(username, password)

            # Authentication through either username or email
            else:
                user = self._validate_username_email(username, email, password)

        else:
            # Authentication without using allauth
            if email:
                try:
                    username = User.objects.get(email__iexact=email).get_username()
                except User.DoesNotExist:
                    pass

            if username:
                user = self._validate_username_email(username, '', password)

        # Did we get back an active user?
        if user:
            if not user.is_active:
                msg = 'this user can not login'
                raise exceptions.ValidationError(msg)
        else:
            msg = '不能使用提供的信息登录'
            raise exceptions.ValidationError(msg)

        # If required, is the email verified?
        if 'rest_auth.registration' in settings.INSTALLED_APPS:
            from allauth.account import app_settings
            if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
                email_address = user.emailaddress_set.get(email=user.email)
                if not email_address.verified:
                    raise serializers.ValidationError('email invalidate')

        return attrs

登录面板如下:


我想将登录面板优化为两个字段。一个用于用户名/电话/电子邮件,另一个用于密码

但是如何更改LoginSerializer

1个回答

4
您可以轻松地用一个CharField替换掉那3个字段(电子邮件/用户名/电话号码),然后尝试查询所有这3个字段以找到匹配的内容,这是最简单的情况。
为了减少数据库查询量,还有一种更加详细的方法,可以使用简单的正则表达式或甚至是简单的检查来区分不同的登录类型。(根据您接受的电话号码的类型,您可能需要使用一些更复杂的检查来确定电话登录,例如 +1 813 3181、+1 (317) 173-1375等)
总而言之,以下类似的内容将非常实用:
def validate(self, attrs):
    id_field = attrs.get('id_field')

    user = None

    if '@' in id_field:
        user = User.objects.filter(email__iexact=id_field).first()
    elif id_field.isdigit():
        user = User.objects.filter(phone_number=id_field).first()
    else:
        user = User.objects.filter(username__iexact=id_field).first()

    if not user:
        raise serializers.ValidationError("User does not exists")

    ...

    return attrs

编辑

要检查找到的用户的密码,您可以使用Django的check_password函数 (Django的check_password函数)

密码验证可能如下所示:

...

if not user.check_password(password):
    raise ValidationError('Invalid password')

...
# Now on, user's password is validated.

如何验证密码,兄弟? - sof-03
@sof-03 你可以使用 user.check_password(pswd) 或者使用 check_password django.contrib.auth.hashers。 - Prateek099

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接