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)
Есть ли какой-либо другой логин помимо первого имени пользователя?
Ответы
Ответ 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')