我们可以通过用户名以及Django中用户名字段中的电子邮件对用户进行身份验证吗?

时间:2018-09-04 22:34:28

标签: django python-3.x django-forms django-views

我正在使用Django内置身份验证。可以通过django登录表单中的用户名和密码登录用户。但我希望用户也能够使用电子邮件ID和密码登录。

登录表单仅具有用户名字段。我们能否使用此登录字段输入电子邮件ID或用户名并验证用户身份。

这是我的django登录视图

class LoginForm(generic.CreateView):
print("login")
form_class = LoginForm
template_name = "feed/SignUp.html"

def get(self, request):
    form = self.form_class(None)
    return render(request, self.template_name, {'form': form})

def post(self, request):
    form = self.form_class(request.POST)
    if form.is_valid():
        UserModel = get_user_model()
        username = request.POST['username']
        password = request.POST['password']

        user = authenticate(request, username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                return redirect('')
    else:
        print(form.errors)

我的想法与我们可以通过用户名或电子邮件登录GitHub帐户一样。我应该怎么做才能做到这一点?

3 个答案:

答案 0 :(得分:0)

您可以检查用户名输入是否为带有以下内容的电子邮件:

from django.core.validators import validate_email

try:
    validate_email(username_field) # If it's a valid email
    username = User.objects.get(email=username_field).username # Get username with email
    authenticate(username=username, password=password_field) # Authenticate that user
except:
    # It's a username, so do the normal authentication

答案 1 :(得分:0)

您可能必须扩展用户模型并添加电子邮件作为字段。此外,您必须更新Manager才能完成工作。

以下代码段仅供您参考。

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin

class UserManager(BaseUserManager):
    """
    Override auth.models.UserManager by extending BaseUserManager.
    We changed _create_user method to take email as username.
    """
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email=None, password=None, **extra_fields):
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_superuser', True)
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    """
        Override Django default User model class by extending AbstractBaseUser.
    """
    email = models.EmailField(_('email address'), blank=False, unique=True, error_messages={ 'unique': _("A user with that email already exists."),})
    is_active = models.BooleanField(_('active'), default=True)

    objects = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'email'

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

    def clean(self):
        super(User, self).clean()
        self.email = self.__class__.objects.normalize_email(self.email)


    def encode_uid(self):
        return urlsafe_base64_encode(force_bytes(self.pk))

您可能必须重写AbstractBaseUser的get_user_name和其他方法。

答案 2 :(得分:0)

使用Django的内置用户模型,我们必须通过覆盖authenticate hereModelBackend方法并添加您的AUTHENTICATION_BACKENDSsettings.py的自定义后端路径。

# project/app/backends.py

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model

class EmailAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None or password is None:
            return
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=username)  # try with email
        except UserModel.DoesNotExist:
            try:
                user = UserModel.objects.get(username=username)  # or username
            except UserModel.DoesNotExist:
                UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
# project/settings.py

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',  # default
    'app.backends.EmailAuthBackend',  # custom
]

# remember to override the login redirect url or it defaults to accounts/profile/
LOGIN_REDIRECT_URL = '/'

文档:https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#authentication-backends

通过这种方式,您仍然可以访问父类的get_user和其余方法,而无需重新实现它们。