Django - 用电子邮件登录

时间:2016-05-19 19:14:17

标签: django

我希望django通过电子邮件验证用户,而不是通过用户名验证用户。一种方法是提供电子邮件值作为用户名值,但我不希望这样。原因是,我有一个网址/profile/<username>/,因此我没有网址/profile/abcd@gmail.com/

另一个原因是所有电子邮件都是唯一的,但有时会发生用户名。因此,我将自动创建用户名fullName_ID

如何更改让Django通过电子邮件进行身份验证?

这就是我创建用户的方式。

username = `abcd28`
user_email = `abcd@gmail.com`
user = User.objects.create_user(username, user_email, user_pass)

这是我登录的方式。

email = request.POST['email']
password = request.POST['password']
username = User.objects.get(email=email.lower()).username
user = authenticate(username=username, password=password)
login(request, user)

除了首先获取用户名之外,还有其他任何登录信息吗?

16 个答案:

答案 0 :(得分:69)

您应该编写自定义身份验证后端。这样的事情会起作用:

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

class EmailBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=username)
        except UserModel.DoesNotExist:
            return None
        else:
            if user.check_password(password):
                return user
        return None

然后,在您的设置中将该后端设置为您的身份验证后端:

AUTHENTICATION_BACKENDS = ['path.to.auth.module.EmailBackend']

<强>更新即可。继承自ModelBackend,因为它已经实现了get_user()之类的方法。

答案 1 :(得分:21)

如果您正在开始一个新项目,django强烈建议您设置自定义用户模型。 (见https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project

如果您这样做,请在您的用户模型中添加三行:

class MyUser(AbstractUser):
    USERNAME_FIELD = 'email'
    email = models.EmailField(_('email address'), unique=True) # changes email to unique and blank to false
    REQUIRED_FIELDS = [] # removes email from REQUIRED_FIELDS

然后authenticate(email=email, password=password)有效,而authenticate(username=username, password=password)停止工作。

答案 2 :(得分:7)

我有一个类似的要求,其中用户名/电子邮件应该用于用户名字段。如果有人正在寻找身份验证后端的方法,请查看以下工作代码。如果您只想要,您可以更改查询集电子邮件。

from django.contrib.auth import get_user_model  # gets the user_model django  default or your own custom
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q


# Class to permit the athentication using email or username
class CustomBackend(ModelBackend):  # requires to define two functions authenticate and get_user

    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()

        try:
            # below line gives query set,you can change the queryset as per your requirement
            user = UserModel.objects.filter(
                Q(username__iexact=username) |
                Q(email__iexact=username)
            ).distinct()

        except UserModel.DoesNotExist:
            return None

        if user.exists():
            ''' get the user object from the underlying query set,
            there will only be one object since username and email
            should be unique fields in your models.'''
            user_obj = user.first()
            if user_obj.check_password(password):
                return user_obj
            return None
        else:
            return None

    def get_user(self, user_id):
        UserModel = get_user_model()
        try:
            return UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

还在settings.py

中添加AUTHENTICATION_BACKENDS =('path.to.CustomBackend',)

答案 3 :(得分:3)

Django 2.x

正如上面Ganesh在django 2.x中提到的那样,authenticate方法现在需要一个请求参数。

# backends.py
from django.contrib.auth import backends, get_user_model
from django.db.models import Q
UserModel = get_user_model()


class ModelBackend(backends.ModelBackend):

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            # user = UserModel._default_manager.get_by_natural_key(username)
            # You can customise what the given username is checked against, here I compare to both username and email fields of the User model
            user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
        return super().authenticate(request, username, password, **kwargs)

将您的后端添加到您的项目设置中

# settings.py
AUTHENTICATION_BACKENDS = ['path.to.ModelBackend']

您的自定义用户模型将需要使活动和经过验证的用户的电子邮件具有唯一性,您可以使用以下方式简单地做到这一点:

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    objects = UserManager()
    email = models.EmailField(_('email address'), unique=True)

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        db_table = 'auth_user'
        swappable = 'AUTH_USER_MODEL'

但是,为防止某人阻止他人使用其电子邮件,您应该添加电子邮件验证,并在注册和登录过程中考虑到电子邮件可能不是唯一的(并可能阻止新用户使用现有的并经过验证的电子邮件地址)

答案 4 :(得分:2)

您应该自定义ModelBackend类。 我的简单代码:

-s "$(echo -e "This is the subject\nX-Priority: 1")"

settings.py 文件中,添加:

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

class YourBackend(ModelBackend):

  def authenticate(self, username=None, password=None, **kwargs):
    UserModel = get_user_model()
    if username is None:
        username = kwargs.get(UserModel.USERNAME_FIELD)
    try:
        if '@' in username:
            UserModel.USERNAME_FIELD = 'email'
        else:
            UserModel.USERNAME_FIELD = 'username'

        user = UserModel._default_manager.get_by_natural_key(username)
    except UserModel.DoesNotExist:
        UserModel().set_password(password)
    else:
        if user.check_password(password) and self.user_can_authenticate(user):
            return user

答案 5 :(得分:1)

from django.contrib.auth.models import User

from django.db import Q

class EmailAuthenticate(object):

    def authenticate(self, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(email=username) | Q(username=username))
        except User.DoesNotExist:
            return None
        except MultipleObjectsReturned:
            return User.objects.filter(email=username).order_by('id').first()

        if user.check_password(password):
            return user
        return None

    def get_user(self,user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

然后在settings.py中输入:

AUTHENTICATION_BACKENDS = (
  'articles.backends.EmailAuthenticate',
)

其中articles是我的django应用程序,backends.py是我的应用程序中的python文件,EmailAuthenticate是我的backends.py文件中的身份验证后端类

答案 6 :(得分:1)

非常简单。不需要任何其他的类。

使用电子邮件创建和更新用户时,只需在电子邮件中设置用户名字段即可。

这样,当您对用户名字段进行身份验证时,它将与电子邮件的值相同。

代码:

# Create
User.objects.create_user(username=post_data['email'] etc...)

# Update
user.username = post_data['email']
user.save()

# When you authenticate
user = authenticate(username=post_data['email'], password=password)

答案 7 :(得分:0)

对于Django 2

username = get_object_or_404(User, email=data["email"]).username
        user = authenticate(
            request, 
            username = username, 
            password = data["password"]
        )
        login(request, user)

答案 8 :(得分:0)

Django 2.X的电子邮件和用户名身份验证

请记住,这是一个常见的问题,这是一个模仿Django source code的自定义实现,但是使用用户名或电子邮件对用户进行身份验证,不区分大小写,保留timing attack {{3} }和protection

from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q

class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
        except UserModel.DoesNotExist:
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

    def get_user(self, user_id):
        try:
            user = UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

        return user if self.user_can_authenticate(user) else None

始终记得将其添加到您的设置中。正确的not authenticating inactive users

答案 9 :(得分:0)

使用Django 2.x的电子邮件和用户名进行身份验证

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q

class EmailorUsernameModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
        except UserModel.DoesNotExist:
            return None
        else:
            if user.check_password(password):
                return user
        return None

在settings.py中,添加以下行

AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend']

答案 10 :(得分:0)

针对Django 2.x的电子邮件身份验证

def admin_login(request):
if request.method == "POST":
    email = request.POST.get('email', None)
    password = request.POST.get('password', None)
    try:
        get_user_name = CustomUser.objects.get(email=email)
        user_logged_in =authenticate(username=get_user_name,password=password)
        if user_logged_in is not None:
            login(request, user_logged_in)
            messages.success(request, f"WelcomeBack{user_logged_in.username}")
            return HttpResponseRedirect(reverse('backend'))
        else:
            messages.error(request, 'Invalid Credentials')
            return HttpResponseRedirect(reverse('admin_login'))
    except:
        messages.warning(request, 'Wrong Email')
        return HttpResponseRedirect(reverse('admin_login'))

else:
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('backend'))
    return render(request, 'login_panel/login.html')

答案 11 :(得分:0)

针对Django 3.x的电子邮件身份验证

要使用电子邮件/用户名和密码进行身份验证,而不是默认的用户名和密码身份验证,我们需要重写ModelBackend类的两种方法:authenticate()和get_user():

get_user方法使用一个user_id(可以是用户名,数据库ID或其他任何内容,但必须对您的用户对象唯一),并返回一个用户对象或None。如果您没有将电子邮件作为唯一键,则必须处理为query_set返回的多个结果。在下面的代码中,已通过从返回的列表中返回第一个用户来解决此问题。

from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q

class EmailBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try: #to allow authentication through phone number or any other field, modify the below statement
            user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
        except UserModel.DoesNotExist:
            UserModel().set_password(password)
        except MultipleObjectsReturned:
            return User.objects.filter(email=username).order_by('id').first()
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

    def get_user(self, user_id):
        try:
            user = UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

        return user if self.user_can_authenticate(user) else None

默认情况下,AUTHENTICATION_BACKENDS设置为:

['django.contrib.auth.backends.ModelBackend']

在settings.py文件中,在底部添加以下内容以覆盖默认值:

AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',)

答案 12 :(得分:0)

如果您创建了自定义数据库,则要从那里验证电子邮件ID和密码。

  1. 使用models.objects.value_list('db_columnname').filter(db_emailname=textbox email)来获取电子邮件ID和密码

2.assign在列表中获取object_query_list

3。将列表转换为字符串

Ex:

  1. 采用HTML Email_idPassword中的值Views.py

    u_email = request.POST.get('uemail')

    u_pass = request.POST.get('upass')

  2. 从数据库中获取电子邮件ID和密码

    Email = B_Reg.objects.values_list('B_Email',flat=True).filter(B_Email=u_email)

    Password = B_Reg.objects.values_list('Password',flat=True).filter(B_Email=u_email)

  3. Query值集中获取列表中的电子邮件ID和密码

    Email_Value = Email[0]

    Password_Value=Password[0]

  4. 将列表转换为字符串

    string_email = ''.join(map(str, Email_Value))

    string_password = ''.join(map(str, Password_Value))

最后您的登录条件

if (string_email==u_email and string_password ==u_pass)

答案 13 :(得分:0)

我为此创建了一个帮助器:函数authenticate_user(email, password)

from django.contrib.auth.models import User


def authenticate_user(email, password):
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist:
        return None
    else:
        if user.check_password(password):
            return user

    return None

class LoginView(View):
    template_name = 'myapp/login.html'

    def get(self, request):
        return render(request, self.template_name)

    def post(self, request):
        email = request.POST['email']
        password = request.POST['password']
        user = authenticate_user(email, password)
        context = {}

        if user is not None:
            if user.is_active:
                login(request, user)

                return redirect(self.request.GET.get('next', '/'))
            else:
                context['error_message'] = "user is not active"
        else:
            context['error_message'] = "email or password not correct"

        return render(request, self.template_name, context)

答案 14 :(得分:0)

似乎此方法已在Django 3.0中更新。

对我来说有效的方法是:

authentication.py#<-我将其放置在应用程序中(在settings.py旁边的项目文件夹中不起作用

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User

class EmailBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=username)
        except UserModel.DoesNotExist:
            return None
        else:
            if user.check_password(password):
                return user
        return None

    def get_user(self, user_id):
        UserModel = get_user_model()
        try:
            return UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

然后将其添加到settings.py文件

AUTHENTICATION_BACKENDS = (
    'appname.authentication.EmailBackend',
)

答案 15 :(得分:0)

默认的用户模型继承/扩展了一个抽象类。框架应该对一定程度的变化或变更保持宽容。

更简单的方法是执行以下操作: 这是在虚拟环境中

  1. 转到您的 django 安装位置并找到 Lib 文件夹
  2. 导航到 django/contrib/auth/
  3. 找到并打开models.py 文件。找到 AbstractUser 类第 315 行

电子邮件属性上的第 336 行添加唯一性并将其设置为 true

email = models.EmailField(_('email address'), blank=True,unique=True)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
  1. 完成、迁移和迁移

风险自负,