django用户模型中有多个USERNAME_FIELD

Sau*_*rma 8 django django-authentication django-users

我的自定义用户模型:

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'
Run Code Online (Sandbox Code Playgroud)

有没有办法指定多个USERNAME_FIELD?有类似的东西['email','username'],用户可以通过电子邮件和用户名登录?

Ala*_*air 10

USERNAME_FIELD设置不支持列表.您可以创建一个自定义身份验证后端,尝试在"电子邮件"或"用户名"字段中查找用户.

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)
Run Code Online (Sandbox Code Playgroud)

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

 AUTHENTICATION_BACKENDS = ('path.to.UsernameOrEmailBackend,)\
Run Code Online (Sandbox Code Playgroud)

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


Rah*_*pta 8

我们可以通过实现自己的电子邮件身份验证后端来实现.

您可以执行以下操作:

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

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

AUTH_USER_MODEL = 'myapp.MyUser'
Run Code Online (Sandbox Code Playgroud)

步骤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
Run Code Online (Sandbox Code Playgroud)

步骤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 
    )
Run Code Online (Sandbox Code Playgroud)

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