拥有用户名和电子邮件,但使用电子邮件对 django-rest-auth 中的用户进行身份验证
Having both username and email but using email to authenticate users in django-rest-auth
在大多数教程中,我看到人们使用电子邮件或用户名。我想同时拥有这两个字段,但只使用电子邮件来使用 Django-rest-auth 对用户进行身份验证,因为电子邮件将被验证并且非常重要。但是用户名在我的应用程序中也很重要。
models.py
class UserManager(BaseUserManager):
def _create_user(self, email, fullname, password, is_staff, is_superuser, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
now = timezone.now()
email = self.normalize_email(email)
fullname = fullname
user = self.model(
email=email,
fullname=fullname,
is_staff=is_staff,
is_active=True,
is_superuser=is_superuser,
last_login=now,
date_joined=now,
**extra_fields
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, fullname, password, **extra_fields):
return self._create_user(email, fullname, password, False, False, **extra_fields)
def create_superuser(self, email, fullname, password, **extra_fields):
user=self._create_user(email, fullname, password, True, True, **extra_fields)
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(max_length=254, unique=True)
fullname = models.CharField(max_length=250)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fullname']
objects = UserManager()
def __str__(self):
return self.email
serializers.py
class CustomRegisterSerializer(RegisterSerializer):
'''
a custom serializer that overides the default rest-auth, and for
the user to register himself
'''
username = None
email = serializers.EmailField(required=True)
password1 = serializers.CharField(write_only=True)
fullname = serializers.CharField(required=True)
def get_cleaned_data(self):
super(CustomRegisterSerializer, self).get_cleaned_data()
return {
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
'fullname': self.validated_data.get('fullname', ''),
}
注意:我正在使用 Django rest auth 来验证用户
您可以使用 ModelBackend
中您自己的身份验证后端 class 并覆盖 authenticate
函数。
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from django.contrib.auth import get_user_model
class EmailAndUsernameBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel.objects.get(Q(email=username) | Q(username=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
您应该在 settings.py
中添加(或替换为 django.contrib.auth.backends.ModelBackend)到 AUTHENTICATION_BACKENDS
例如:
AUTHENTICATION_BACKENDS = [
...
'users.backends.EmailBackend',
]
注意:如果您有其他身份验证后端,例如 OAuth 或社交登录,您应该将您的后端添加到列表末尾。
在大多数教程中,我看到人们使用电子邮件或用户名。我想同时拥有这两个字段,但只使用电子邮件来使用 Django-rest-auth 对用户进行身份验证,因为电子邮件将被验证并且非常重要。但是用户名在我的应用程序中也很重要。
models.py
class UserManager(BaseUserManager):
def _create_user(self, email, fullname, password, is_staff, is_superuser, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
now = timezone.now()
email = self.normalize_email(email)
fullname = fullname
user = self.model(
email=email,
fullname=fullname,
is_staff=is_staff,
is_active=True,
is_superuser=is_superuser,
last_login=now,
date_joined=now,
**extra_fields
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, fullname, password, **extra_fields):
return self._create_user(email, fullname, password, False, False, **extra_fields)
def create_superuser(self, email, fullname, password, **extra_fields):
user=self._create_user(email, fullname, password, True, True, **extra_fields)
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(max_length=254, unique=True)
fullname = models.CharField(max_length=250)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fullname']
objects = UserManager()
def __str__(self):
return self.email
serializers.py
class CustomRegisterSerializer(RegisterSerializer):
'''
a custom serializer that overides the default rest-auth, and for
the user to register himself
'''
username = None
email = serializers.EmailField(required=True)
password1 = serializers.CharField(write_only=True)
fullname = serializers.CharField(required=True)
def get_cleaned_data(self):
super(CustomRegisterSerializer, self).get_cleaned_data()
return {
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
'fullname': self.validated_data.get('fullname', ''),
}
注意:我正在使用 Django rest auth 来验证用户
您可以使用 ModelBackend
中您自己的身份验证后端 class 并覆盖 authenticate
函数。
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from django.contrib.auth import get_user_model
class EmailAndUsernameBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel.objects.get(Q(email=username) | Q(username=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
您应该在 settings.py
例如:
AUTHENTICATION_BACKENDS = [
...
'users.backends.EmailBackend',
]
注意:如果您有其他身份验证后端,例如 OAuth 或社交登录,您应该将您的后端添加到列表末尾。