【问题标题】:Multiple USERNAME_FIELD in django user modeldjango 用户模型中的多个 USERNAME_FIELD
【发布时间】:2015-09-30 22:26:50
【问题描述】:

我的自定义用户模型:

class MyUser(AbstractBaseUser):
    username = models.CharField(unique=True,max_length=30)
    email = models.EmailField(unique=True,max_length=75)
    is_staff = models.IntegerField(default=False)
    is_active = models.IntegerField(default=False)
    date_joined = models.DateTimeField(default=None)

    # Use default usermanager
    objects = UserManager()

    USERNAME_FIELD = 'email'

有没有办法指定多个 USERNAME_FIELD ?像['email','username'] 这样用户可以通过电子邮件和用户名登录?

【问题讨论】:

    标签: django django-authentication django-users


    【解决方案1】:

    USERNAME_FIELD 设置不支持列表。您可以创建一个custom authentication backend,尝试在“电子邮件”或“用户名”字段中查找用户。

    from django.db.models import Q
    
    from django.contrib.auth import get_user_model
    
    MyUser = get_user_model()
    
    class UsernameOrEmailBackend(object):
        def authenticate(self, username=None, password=None, **kwargs):
            try:
               # Try to fetch the user by searching the username or email field
                user = MyUser.objects.get(Q(username=username)|Q(email=username))
                if user.check_password(password):
                    return user
            except MyUser.DoesNotExist:
                # Run the default password hasher once to reduce the timing
                # difference between an existing and a non-existing user (#20760).
                MyUser().set_password(password)
    

    然后,在您的settings.py 中将AUTHENTICATION_BACKENDS 设置为您的身份验证后端:

     AUTHENTICATION_BACKENDS = ('path.to.UsernameOrEmailBackend,)\
    

    请注意,此解决方案并不完美。例如,密码重置仅适用于您在 USERNAME_FIELD 设置中指定的字段。

    【讨论】:

    • 请注意,在默认的 django 实现中,email 字段不是唯一的...安全、怪异等 AHOI。
    【解决方案2】:

    不幸的是,不是开箱即用的。

    auth contrib 模块断言 USERNAME_FIELD 值是单值的。

    https://github.com/django/django/search?q=USERNAME_FIELD

    如果你想拥有一个多值的 USERNAME_FIELD,你要么必须编写相应的逻辑,要么找到一个允许它的包。

    【讨论】:

      【解决方案3】:

      不,您不能在USERNAME_FIELD 中定义多个字段。

      一种选择是编写您自己的自定义登录名来自己检查这两个字段。 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/

      即将后端更改为您自己的。 AUTHENTICATION_BACKENDS 然后编写一个身份验证方法并检查数据库中两个字段的用户名。

      PS 你可能想在你的模型上使用unique_together,这样你就不会遇到问题。

      另一种选择是使用实际字段username 来存储字符串和电子邮件。

      【讨论】:

        【解决方案4】:

        我们可以通过实现我们自己的电子邮件身份验证后端来做到这一点。

        您可以执行以下操作:

        第 1 步在设置中替换自定义用户模型:

        由于我们不会使用 Django 的默认 User 模型进行身份验证,我们需要在 settings.py 中定义我们的自定义 MyUser 模型。在项目的设置中将MyUser 指定为AUTH_USER_MODEL

        AUTH_USER_MODEL = 'myapp.MyUser'
        

        Step-2 编写自定义身份验证后端的逻辑:

        要编写我们自己的身份验证后端,我们需要实现至少两种方法,即get_user(user_id)authenticate(**credentials)

        from django.contrib.auth import get_user_model
        from django.contrib.auth.models import check_password
        
        class MyEmailBackend(object):
            """
            Custom Email Backend to perform authentication via email
            """
            def authenticate(self, username=None, password=None):
                my_user_model = get_user_model()
                try:
                    user = my_user_model.objects.get(email=username)
                    if user.check_password(password):
                        return user # return user on valid credentials
                except my_user_model.DoesNotExist:
                    return None # return None if custom user model does not exist 
                except:
                    return None # return None in case of other exceptions
        
            def get_user(self, user_id):
                my_user_model = get_user_model()
                try:
                    return my_user_model.objects.get(pk=user_id)
                except my_user_model.DoesNotExist:
                    return None
        

        Step-3 在设置中指定自定义身份验证后端:

        编写自定义身份验证后端后,在AUTHENTICATION_BACKENDS 设置中指定此身份验证后端。

        AUTHENTICATION_BACKENDS 包含要使用的身份验证后端列表。 Django 尝试在其所有身份验证后端进行身份验证。如果第一个身份验证方法失败,Django 会尝试第二个,依此类推,直到尝试了所有后端。

        AUTHENTICATION_BACKENDS = (
            'my_app.backends.MyEmailBackend', # our custom authentication backend
            'django.contrib.auth.backends.ModelBackend' # fallback to default authentication backend if first fails 
            )
        

        如果通过MyEmailBackend 的身份验证失败,即无法通过email 对用户进行身份验证,那么我们使用Django 的默认身份验证ModelBackend,它将尝试通过MyUser 模型的username 字段进行身份验证。

        【讨论】:

        • 我现在创建了类似的自定义身份验证后端,我想在登录此方法时也传递电子邮件和电话号码字段。但我只得到用户名和密码字段 kwargs 是空白的任何想法如何获取所有字段?
        • 您不需要 from django.contrib.auth.models import check_password 它已经是 auth_user_model 对象的属性。否则很好的解决方案。
        【解决方案5】:

        如果您的 USERNAME_FIELD 是 username 并且用户使用 email 登录,也许您可​​以使用提供的 email 编写获取 username 的代码,然后将 username 与 @987654326 一起使用@ 进行身份验证。

        【讨论】:

          【解决方案6】:

          REQUIRED_FIELDS = []
          你可以定义多个 username_fields

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-06-07
            • 2013-12-23
            • 2021-08-20
            • 1970-01-01
            • 2019-08-30
            • 2019-11-03
            • 2019-06-25
            • 1970-01-01
            相关资源
            最近更新 更多