通过扩展用户模型中的电话字段登录

Posted

技术标签:

【中文标题】通过扩展用户模型中的电话字段登录【英文标题】:Login via Phone field in Extended User Model 【发布时间】:2020-01-08 03:07:44 【问题描述】:

我使用了 django 用户模型并将其扩展为添加电话字段。我可以使用用户名或电子邮件登录,但无法从扩展用户模型访问电话号码字段。

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phonenumber = models.CharField(max_length=10)

后端.py

class AuthenticationBackend(backends.ModelBackend):
    def authenticate(self, request,  username=None, password=None, **kwargs):
        usermodel = get_user_model()
        print(usermodel)

        try:
            user = usermodel.objects.get(Q(username__iexact=username) | Q(
                email__iexact=username))
            if user.check_password(password):
                return user
        except user.DoesNotExist:
            pass

backend.py 是我用来通过用户名或电子邮件实现登录的,但我无法在扩展用户模型中对 phonenumber 执行此操作。

【问题讨论】:

您可以显示您尝试通过 phone_number 获取用户时的代码吗? 我没有尝试通过电话号码获取用户。我被困在这里。我不知道如何在扩展用户模型中访问电话号码 你可以试试usermodel.objects.get(Q(profile__phonenumber=some_phone_number))。从UserProfile 的关系就是profile。但是你应该让phonenumber 在你的模型上是唯一的,否则你会有多个用户使用相同的电话号码的风险,例外​​不会是usermodel.DoesNotExist,而是usermodel.MultipleObjectsReturned 我认为,如果您想使用电话号码作为身份验证字段,那么您最好扩展 AbstractBaseUser 类,而不是像您一样将您的个人资料映射到 User 。请参阅此处了解更多信息:simpleisbetterthancomplex.com/tutorial/2016/07/22/… 但正如@urbanespaceman 所提到的,在这种情况下,最好创建您的自定义User 模型,正如here 所解释的那样。 【参考方案1】:

有两种方法可以解决您的问题。

    通过继承用户模型并更改默认用户模型来扩展用户模型。我建议您走这条路线,因为电话号码用于身份验证。 在 Profile 上设置 related_name,并根据该名称查询 User 模型。

对于第一个,我建议您查看Django documentation on creating custom users. 还有一个关于如何做到这一点的相当广泛的教程here。

如果你想走简单的路,你只需要在个人资料的电话号码字段上设置一个反向访问器。

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phonenumber = models.CharField(max_length=10, related_name='profile')

然后您可以通过用户个人资料的电话号码搜索用户:

class AuthenticationBackend(backends.ModelBackend):
    def authenticate(self, request,  username=None, password=None, **kwargs):
        usermodel = get_user_model()
        print(usermodel)

        try:
            user = usermodel.objects.get(Q(username__iexact=username) | Q(
                email__iexact=username) | Q(profile__phonenumber__iexact=username)
            if user.check_password(password):
                return user
        except user.DoesNotExist:
            pass

虽然这不在您的问题范围内,但我认为您应该注意您的代码存在以下问题:

电话号码通常比 10 个字符的字符串更复杂。 +31 6 12345678,是一个有效的电话号码,但超过 10 个字符。查看 this question 获取有关如何存储和验证电话号码的指导。 如果您使用字段进行身份验证,请确保它是唯一的。 phonenumber 字段实际上应该是phonenumber = models.CharField(max_length=10, related_name='profile', unique=True) 如果有电话号码为“0123456789”的用户和用户名“0123456789”的其他用户,您的usermodel.objects.get(...) 查询将返回多个用户。您应该限制用户名不包含电话号码,这只能通过扩展默认的 User 类来实现。

【讨论】:

【参考方案2】:

您可以扩展 AbstractUser 并在其上添加电话号码。

class User(AbstractUser):
    phonenumber = models.CharField(max_length=10)

    USERNAME_FIELD = 'phonenumber'

那么你应该在settings.py中将自定义模型指定为默认用户模型 AUTH_USER_MODEL = 'app_name.User'

Customizing authentication in Django

【讨论】:

以上是关于通过扩展用户模型中的电话字段登录的主要内容,如果未能解决你的问题,请参考以下文章

如何将电话号码字段添加到 django UserCreationForm?

Firebase Listener 在某些用户通过电话身份验证登录期间不起作用

通过回调或猫鼬模型验证 PassportJS?

Symfony 3 通过手机阵列登录

在 IOS 中使用电话号码登录 Firebase

无法使用测试用户通过 Facebook iOS SDK 3 登录