Подтвердить что ты не робот

Django - Войти через E-mail

Я хочу, чтобы django аутентифицировал пользователей по электронной почте, а не через usernames. Один из способов может предоставить значение электронной почты как значение имени пользователя, но я этого не хочу. Причина в том, что у меня есть url /profile/<username>/, поэтому у меня не может быть url /profile/[email protected]/.

Другая причина в том, что все электронные письма уникальны, но иногда случается, что имя пользователя уже принято. Следовательно, я автоматически создаю имя пользователя как fullName_ID.

Как я могу просто изменить, пусть Django аутентифицируется с помощью электронной почты?

Вот как я создаю пользователя.

username = `abcd28`
user_email = `[email protected]`
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)

Есть ли какой-либо другой логин помимо первого имени пользователя?

4b9b3361

Ответ 1

Вы должны написать собственный сервер аутентификации. Что-то вроде этого будет работать:

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().

Ответ 2

Если вы начинаете новый проект, 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) перестает работать.

Ответ 3

У меня было аналогичное требование, когда либо имя пользователя/адрес электронной почты должно работать для поля имени пользователя. В случае, если кто-то ищет способ проверки подлинности для этого, проверьте следующий рабочий код. Вы можете изменить запрос, если хотите только электронной почты.

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

Также добавьте AUTHENTICATION_BACKENDS = ('путь .to.CustomBackend',) в settings.py

Ответ 4

Джанго 2.х

Как упомянуто Ганешем выше для django 2.x, метод authenticate теперь требует param запроса.

# 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'

Но чтобы не допустить, чтобы кто-то блокировал использование электронной почты кем-то другим, вместо этого вы должны добавить проверку электронной почты и учесть, что ваши процессы регистрации и входа в систему учитывают, что электронные письма могут быть не уникальными (и, вероятно, не позволят новым пользователям использовать существующий и проверенный адрес электронной почты).

Ответ 5

Вы должны настроить класс ModelBackend. Мой простой код:

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

И в файле settings.py добавьте:

AUTHENTICATION_BACKENDS = ['path.to.class.YourBackend']

Ответ 6

Проверка подлинности электронной почты и имени пользователя для Django 2.X

Имея в виду, что это распространенный вопрос, здесь пользовательская реализация, имитирующая исходный код Django, но аутентифицирующая пользователя с помощью имени пользователя или электронной почты, без учета регистра, сохраняя защиту от временных атак и не аутентифицируя неактивных пользователей.

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

Всегда не забывайте добавлять в ваши settings.py правильный бэкэнд аутентификации.

Ответ 7

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',
)

где статьи - мое django-приложение, backends.py - файл python внутри моего приложения, а EmailAuthenticate - класс серверной части для аутентификации внутри моего файла backends.py

Ответ 8

Для Джанго 2

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

Ответ 9

Аутентификация с помощью электронной почты и имени пользователя для 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

Аутентификация по электронной почте для 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')