使用Django中的电子邮件地址或用户名登录用户

use*_*276 25 python django django-authentication django-login

我正在尝试创建一个auth后端,以允许我的用户使用他们的电子邮件地址或Django 1.6中的用户名使用自定义用户模型登录.当我使用用户名登录时后端工作,但由于某种原因没有电子邮件.有什么我忘了做的事吗?

from django.conf import settings
from django.contrib.auth.models import User

class EmailOrUsernameModelBackend(object):
    """
    This is a ModelBacked that allows authentication with either a username or an email address.

    """
    def authenticate(self, username=None, password=None):
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:
            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, username):
        try:
            return User.objects.get(pk=username)
        except User.DoesNotExist:
            return None
Run Code Online (Sandbox Code Playgroud)

编辑:建议我从ModelBackend继承并在我的设置中安装它在我的设置中我有这个AUTHENTICATION_BACKENDS =('users.backends','django.contrib.auth.backends.ModelBackend',)我已经将后端更改为这个:

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.backends import ModelBackend
class EmailOrUsernameModelBackend(ModelBackend):
    """
    This is a ModelBacked that allows authentication with either a username or an email address.

    """
    def authenticate(self, username=None, password=None):
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:
            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, username):
        try:
            return User.objects.get(pk=username)
        except User.DoesNotExist:
            return None
Run Code Online (Sandbox Code Playgroud)

现在我收到一个Module "users" does not define a "backends" attribute/class错误.

1bi*_*fMe 20

又一个解决方案:

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


class EmailOrUsernameModelBackend(ModelBackend):
    """
    Authentication backend which allows users to authenticate using either their
    username or email address

    Source: https://stackoverflow.com/a/35836674/59984
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        # n.b. Django <2.1 does not pass the `request`

        user_model = get_user_model()

        if username is None:
            username = kwargs.get(user_model.USERNAME_FIELD)

        # The `username` field is allows to contain `@` characters so
        # technically a given email address could be present in either field,
        # possibly even for different users, so we'll query for all matching
        # records and test each one.
        users = user_model._default_manager.filter(
            Q(**{user_model.USERNAME_FIELD: username}) | Q(email__iexact=username)
        )

        # Test whether any matched user has the provided password:
        for user in users:
            if user.check_password(password):
                return user
        if not users:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (see
            # https://code.djangoproject.com/ticket/20760)
            user_model().set_password(password)
Run Code Online (Sandbox Code Playgroud)

修正:

  • 默认情况下,@用户名字段中不禁止,因此除非自定义用户模型禁止使用@符号,否则不能用于区分用户名和电子邮件.
  • 从技术上讲,可以有两个用户使用相同的电子邮件,一个在电子邮件字段中,另一个在用户名中.除非这种可能性受到限制,否则可能导致用户无法进行身份验证,或者使用未处理的MultipleObjectsReturned异常UserModel._default_manager.get(Q(username__iexact=username) | Q(email__iexact=username)).
  • 捕获任何异常except:通常是不好的做法

缺点 - 如果有两个用户,使用相同的电子邮件,一个在用户名中,另一个在电子邮件中,并且他们有相同的密码,那么它很容易验证第一个匹配.我猜这种可能性很小.

另请注意:任何方法都应email在User模型中强制使用唯一字段,因为默认的User模型未定义唯一的电子邮件,这会导致在使用情况下出现未处理的异常User.objects.get(email__iexact="..."),或者验证第一个匹配项.在任何情况下,使用电子邮件登录都假定电子邮件是唯一的.


use*_*276 11

按照上面给出的建议并改变后AUTHENTICATION_BACKENDS = ['yourapp.yourfile.EmailOrUsernameModelBackend']我得到了错误Manager isn't available; User has been swapped for 'users.User'.这是因为我使用默认的User模型而不是我自己的自定义模型.这是工作代码.

from django.conf import settings
from django.contrib.auth import get_user_model

class EmailOrUsernameModelBackend(object):
    """
    This is a ModelBacked that allows authentication with either a username or an email address.

    """
    def authenticate(self, username=None, password=None):
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:
            user = get_user_model().objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, username):
        try:
            return get_user_model().objects.get(pk=username)
        except get_user_model().DoesNotExist:
            return None
Run Code Online (Sandbox Code Playgroud)


Ste*_*eve 6

我以为我会把更简单的方法吸引给遇到此问题的其他人:

# -*- coding: utf-8 -*-
from django.contrib.auth import backends, get_user_model
from django.db.models import Q


class ModelBackend(backends.ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()

        try:
            user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))

            if user.check_password(password):
                return user
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            UserModel().set_password(password)
Run Code Online (Sandbox Code Playgroud)

注意:

  • 可以忽略USERNAME_FIELD,尽管您可以轻松地将其重新添加
  • 不区分大小写(您可以只删除的,__iexact以使其不区分大小写)


小智 6

我知道这个问题已经得到解答,但是我找到了一种真正巧妙的方法来使用 Django 身份验证视图通过电子邮件和用户名实现登录。我没有看到有人使用这种方法,所以我想为了简单起见我会分享它。

from django.contrib.auth.models import User


class EmailAuthBackend():
    def authenticate(self, username=None, password=None):
        try:
            user = User.objects.get(email=username)
            if user.check_password(raw_password=password):
                return user
            return None
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None
Run Code Online (Sandbox Code Playgroud)

然后在你的settings.py中添加这个

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'myapp.authentication.EmailAuthBackend',
)
Run Code Online (Sandbox Code Playgroud)


kri*_*dha 6

我通过两个简单的步骤为此编写了代码:

  1. VIEWS.py
     if request.method == 'POST':
            userinput = request.POST['username']

            try:
                username = userbase.objects.get(email=userinput).username
            except userbase.DoesNotExist:
                username = request.POST['username']
            password = request.POST['password']
Run Code Online (Sandbox Code Playgroud)
  1. INDEX.html

    我创建了 2 个输入字段,第一个用于用户名/电子邮件。我接受给出的任何输入,并尝试在数据库的电子邮件列中搜索相同的数据,如果匹配,我返回用户名,然后尝试进行身份验证,如果不匹配,我直接使用输入作为用户名。

我正在使用 Django 2.2


小智 5

您可以简单地使用 Try 块来执行此操作..使用:

email = request.POST['username'] 
raw_password = request.POST['password'] 

   try:
        account = authenticate(username=MyUserAccount.objects.get(email=email).username,password=raw_password)
        if account is not None:
            login(request, account)
            return redirect('home')

    except:
        account = authenticate(username=email, password=raw_password)
        if account is not None:
            login(request, account)
            return redirect('home')
Run Code Online (Sandbox Code Playgroud)