Django - Login with Email
Asked Answered
B

18

132

I want django to authenticate users via email, not via usernames. One way can be providing email value as username value, but I dont want that. Reason being, I've a url /profile/<username>/, hence I cannot have a url /profile/[email protected]/.

Another reason being that all emails are unique, but it happen sometimes that the username is already being taken. Hence I'm auto-creating the username as fullName_ID.

How can I just change let Django authenticate with email?

This is how I create a user.

username = `abcd28`
user_email = `[email protected]`
user = User.objects.create_user(username, user_email, user_pass)

This is how I login.

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)

Is there any other of of login apart from getting the username first?

Bureaucratic answered 19/5, 2016 at 19:14 Comment(0)
W
145

You should write a custom authentication backend. Something like this will work:

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

class EmailBackend(ModelBackend):
    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

Then, set that backend as your auth backend in your settings:

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

Updated. Inherit from ModelBackend as it implements methods like get_user() already.

See docs here: https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#writing-an-authentication-backend

Wanda answered 19/5, 2016 at 19:26 Comment(18)
Using django 1.9.8 I've got an error: 'EmailBackend' object has no attribute 'get_user'. Solved by adding 'get_user' method according to this https://mcmap.net/q/75740/-custom-authentication-backend-djangoMcmullin
Please specify for which Django version this code can work. Some are complaining about the get_user method missing.Rap
Rather than just if user.check_password(password): you probably want to include what Django does by default via ModelBackend: if user.check_password(password) and self.user_can_authenticate(user): in order to check that the user has is_active=True.Lubricous
Isn't this vulnerable to a timing attack as it doesn't include the Django mitigation on the source code?Bamberg
Now, the body of a request should contain fields such as a username and a password. Is there any way to change it to an email and a password?Spenser
AUTHENTICATE_BACKENDS = ['app.models.EmailBackend'] worked for meEmera
@GabrielGarcia can You please elaborate I like to know how this is vulnerableEmera
@AzharUddinSheikh It's vulnerable to a timing attack as per my answer; if the user is not found it won't check the password which doesn't run the hashing algorithm which will result in a faster response, so if the attacker gets a response that takes longer than usual means the user exists (as it had to check the password which involves a hash function). My response, which is the way Django implemented on their code (as per my answer), will always hash the password, obfuscating any timing information.Bamberg
@AzharUddinSheikh I would appreciate the upvote so fewer people Googling that implements vulnerable code.Bamberg
@GabrielGarcia I am new in software development I don't know how you figure it out but your answer makes a lot of senseEmera
this is a bad advice. Talking about this line: "user = UserModel.objects.get(email=username)" it's a bad code smell. Regrettably a common one - a dude I took a Udemy course from sheepishly used signals for this similar hackLax
@alexakarpov: Why?Wanda
sorry if I've offended you - but it appears to be a hack. Emails are emails, and usernames are usernames. We don't confuse them in other places, like frontend here, where emails are processed and cleaned in their own ways... it is possible, and this is where I lack experience, that deep in Django backend login is only implemented with expectation of a 'username', no abstract "principal" concept. In which case I am clearly wrongLax
I do see that AbstractBaseUser has this line: " USERNAME_FIELD = 'username'", and I know we can add an override in our setting like USERNAME_FIELD = 'email'. Which, if I understand it correctly, is much cleaner (but if I don't, then I owe you my apologies).Lax
@alexakarpov: Many applications use email addresses as usernames nowadays; in fact, it's becoming more and more common to reuse an email address as a username, rather than make users come up with a username (it is become harder and harder to create unique usernames). My Apple ID, Google account, Outlook account, and even Stack Overflow logins are all email addresses rather than a separate username.Wanda
of course mate, this wasn't at all what triggered my initial reaction; not the fact that we're using emails as principals, but the hacky approach proposedLax
@alexakarpov: Sure, but what is "hacky" about it?Wanda
Is this a safe approach? in terms of security does it create vulnerabilities? (it does work but I worry about the security side)Conyers
G
86

If you’re starting a new project, django highly recommended you to set up a custom user model. (see https://docs.djangoproject.com/en/dev/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project)

and if you did it, add three lines to your user model:

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

Then authenticate(email=email, password=password) works, while authenticate(username=username, password=password) stops working.

Gorham answered 4/4, 2017 at 13:56 Comment(5)
When running createsuperuser, this itself throws an error: TypeError: create_superuser() missing 1 required positional argument: 'username'. You need to use custom user manager: class MyUserManager(BaseUserManager): def create_superuser(self, email, password, **kwargs): user = self.model(email=email, is_staff=True, is_superuser=True, **kwargs) user.set_password(password) user.save() return userSulfate
Complete instructions here: fomfus.com/articles/…Diaconicum
Then again, the Django docs advise against using a custom user model if you are creating a reusable app.Tonguing
isn't this solution very longEmera
@AzharUddinSheikh In other solutions, you'll end up with an improper admin section.Stinko
G
38

Email authentication for Django 3.x

For using email/username and password for authentication instead of the default username and password authentication, we need to override two methods of ModelBackend class: authenticate() and get_user():

The get_user method takes a user_id – which could be a username, database ID or whatever, but has to be unique to your user object – and returns a user object or None. If you have not kept email as a unique key, you will have to take care of multiple result returned for the query_set. In the below code, this has been taken care of by returning the first user from the returned list.

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

By default, AUTHENTICATION_BACKENDS is set to:

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

In settings.py file, add following at the bottom to override the default:

AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',)
Galvin answered 22/12, 2019 at 6:11 Comment(4)
This is great, thanks. I've pretty much completed a project, templates, forms, views, the lot, so starting again isn't that appealing! Now I can authenticate on email address is there any way to remove the username field so it's not included in the authentication and the forms rendered in the templates?Supervision
Why use this instead of USERNAME_FIELD variable within the model?Blockhead
so you can login with both an email and a usernameStier
Thanks Man. Your explanation was greatTrebizond
U
30

Django 4.0

There are two main ways you can implement email authentication, taking note of the following:

  • emails should not be unique on a user model to mitigate misspellings and malicious use.
  • emails should only be used for authentication if they are verified (as in we have sent a verification email and they have clicked the verify link).
  • We should only send emails to verified email addresses.

Custom User Model

A custom user model is recommended when starting a new project as changing mid project can be tricky.

We will add an email_verified field to restrict email authentication to users with a verified email address.

# app.models.py
from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    email_verified = models.BooleanField(default=False)

We will then create a custom authentication backend that will substitute a given email address for a username.

This backend will work with authentication forms that explicitly set an email field as well as those setting a username field.

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

UserModel = get_user_model()


class CustomUserModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD, kwargs.get(UserModel.EMAIL_FIELD))
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get(
                Q(username__exact=username) | (Q(email__iexact=username) & Q(email_verified=True))
            )
        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

We then modify our projects settings.py to use our custom user model and authentication backend.

# project.settings.py

AUTH_USER_MODEL = "app.User"
AUTHENTICATION_BACKENDS = ["app.backends.CustomUserModelBackend"]

Be sure that you run manage.py makemigrations before you migrate and that the first migration contains these settings.

Extended User Model

While less performant than a custom User model (requires a secondary query), it may be better to extend the existing User model in an existing project and may be preferred depending on login flow and verification process.

We create a one-to-one relation from EmailVerification to whichever User model our project is using through the AUTH_USER_MODEL setting.

# app.models.py
from django.conf import settings
from django.db import models


class EmailVerification(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_query_name="verification"
    )
    verified = models.BooleanField(default=False)

We can also create a custom admin that includes our extension inline.

# app.admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin

from .models import EmailVerification

UserModel = get_user_model()


class VerificationInline(admin.StackedInline):
    model = EmailVerification
    can_delete = False
    verbose_name_plural = 'verification'


class UserAdmin(BaseUserAdmin):
    inlines = (VerificationInline,)


admin.site.unregister(UserModel)
admin.site.register(UserModel, UserAdmin)

We then create a backend similar to the one above that simply checks the related models verified field.

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

UserModel = get_user_model()


class ExtendedUserModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD, kwargs.get(UserModel.EMAIL_FIELD))
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get(
                Q(username__exact=username) | (Q(email__iexact=username) & Q(verification__verified=True))
            )
        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

We then modify our projects settings.py to use our authentication backend.

# project.settings.py

AUTHENTICATION_BACKENDS = ["app.backends.ExtendedUserModelBackend"]

You can then makemigrations and migrate to add functionality to an existing project.

Notes

  • if usernames are case insensitive change Q(username__exact=username) to Q(username__iexact=username).
  • In production prevent a new user registering with an existing verified email address.
Undersea answered 26/2, 2019 at 15:50 Comment(4)
Thanks for great answer, but, what does UserModel().set_password(password) do ?Ramage
I don't understand your comment that emails should NOT be unique -- what do misspellings have to do with anything? It seems that emails should be unique, or else you could end up with two different users entering the same email.Ludwog
@Ludwog There's no guarantee that a user owns the email address they enter (malicious use). You can use constraints and checks to prevent two users sharing the same verified email address docs.djangoproject.com/en/4.2/ref/models/constraints.Undersea
@Ramage Hashes the password on an empty user object to prevent vulnerabilities where someone could determine whether a user account exists based on the time it takes the request to complete: code.djangoproject.com/ticket/20760Bircher
A
14

I had a similar requirement where either username/email should work for the username field.In case someone is looking for the authentication backend way of doing this,check out the following working code.You can change the queryset if you desire only the email.

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

Also add AUTHENTICATION_BACKENDS = ( 'path.to.CustomBackend', ) in settings.py

Accepter answered 3/3, 2017 at 12:33 Comment(4)
This worked for me until I upgraded from 1.11 to 2.1.5. Any idea why it won't work with this version?Crossquestion
@Crossquestion add request to the authenticate method's parameters. See docs.djangoproject.com/en/2.2/topics/auth/customizing/…Christinachristine
It also leaves you open to a timing attack, it's worth trying to closely mimicking Django implementation to prevent such vulnerabilities: github.com/django/django/blob/master/django/contrib/auth/…Bamberg
This will also enable inactive users to authenticate.Bamberg
B
6

Email and Username Authentication for Django 2.X

Having in mind that this is a common question, here's a custom implementation mimicking the Django source code but that authenticates the user with either username or email, case-insensitively, keeping the timing attack protection and not authenticating inactive users.

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

Always remember to add it your settings.py the correct Authentication Backend.

Bamberg answered 22/7, 2019 at 21:25 Comment(2)
Is my understanding right that the UserModel().set_password(password) is there to prevent attackers from determining if a user does or doesn't exist by performing roughly the same amount of cryptographic work regardless (I assume this is the timing attack you meant)?Illative
@GrandPhuba You're 100% correctBamberg
P
5

It seems that the method of doing this has been updated with Django 3.0.

A working method for me has been:

authentication.py # <-- I placed this in an app (did not work in the project folder alongside 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

Then added this to the settings.py file

AUTHENTICATION_BACKENDS = (
    'appname.authentication.EmailBackend',
)
Podophyllin answered 11/8, 2020 at 11:0 Comment(0)
J
4

I have created a helper for that: function 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)
Jungian answered 25/3, 2020 at 14:55 Comment(1)
Simple and straightfoward solution! It will work, unless you have multiple users under the same email. It's a pretty nice implementationScarito
T
3

Authentication with Email and Username For 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

In settings.py, add following line,

AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend']
Thema answered 24/7, 2019 at 6:7 Comment(0)
D
3

July, 2023 Update:

You can set up authentication with email and password instead of username and password and in this instruction, username is removed and I tried not to change the default Django settings as much as possible. *You can also see my answer explaining how to extend User model with OneToOneField() to add extra fields and you can see my answer and my answer explaining the difference between AbstractUser and AbstractBaseUser.

First, run the command below to create account app:

python manage.py startapp account

Then, set account app to INSTALLED_APPS and set AUTH_USER_MODEL = 'account.User' in settings.py as shown below:

# "settings.py"

INSTALLED_APPS = [
    ...
    "account", # Here
]

AUTH_USER_MODEL = 'account.User' # Here

Then, create managers.py just under account folder and create UserManager class extending (UM)UserManager in managers.py as shown below. *Just copy & paste the code below to managers.py and managers.py is necessary to make the command python manage.py createsuperuser work properly without any error:

# "account/managers.py"

from django.contrib.auth.models import UserManager as UM
from django.contrib.auth.hashers import make_password

class UserManager(UM):
    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.password = make_password(password)
        user.save(using=self._db)
        return user

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

    def create_superuser(self, email=None, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)

        if extra_fields.get("is_staff") is not True:
            raise ValueError("Superuser must have is_staff=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)

Then, create User model extending AbstractUser and remove username by setting it None and set email with unique=True and set email to USERNAME_FIELD and set UserManager to objects in account/models.py as shown below. *Just copy & paste the code below to account/models.py:

# "account/models.py"

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractUser
from .managers import UserManager

class User(AbstractUser):
    username = None # Here
    email = models.EmailField(_("email address"), unique=True) # Here
    
    USERNAME_FIELD = 'email' # Here
    REQUIRED_FIELDS = []

    objects = UserManager() # Here

Or, you can also create User model extending AbstractBaseUser and PermissionsMixin as shown below. *This code below with AbstractBaseUser and PermissionsMixin is equivalent to the code above with AbstractUser:

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils import timezone
from .managers import UserManager

class User(AbstractBaseUser, PermissionsMixin):
    first_name = models.CharField(_("first name"), max_length=150, blank=True)
    last_name = models.CharField(_("last name"), max_length=150, blank=True)
    email = models.EmailField(_("email address"), unique=True)
    is_staff = models.BooleanField(
        _("staff status"),
        default=False,
        help_text=_("Designates whether the user can log into this admin site."),
    )
    is_active = models.BooleanField(
        _("active"),
        default=True,
        help_text=_(
            "Designates whether this user should be treated as active. "
            "Unselect this instead of deleting accounts."
        ),
    )
    date_joined = models.DateTimeField(_("date joined"), default=timezone.now)

    USERNAME_FIELD = 'email'

    objects = UserManager() # Here

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

*Don't extend DefaultUser(User) model as shown below otherwise there is error:

# "account/models.py"

from django.contrib.auth.models import User as DefaultUser

class User(DefaultUser):
    ...

Then, create UserAdmin class extending UA(UserAdmin) in account/admin.py as shown below. *Just copy & paste the code below to account/admin.py:

from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.admin import UserAdmin as UA
from .models import User

@admin.register(User)
class UserAdmin(UA):
    fieldsets = (
        (None, {"fields": ("password",)}),
        (_("Personal info"), {"fields": ("first_name", "last_name", "email")}),
        (
            _("Permissions"),
            {
                "fields": (
                    "is_active",
                    "is_staff",
                    "is_superuser",
                    "groups",
                    "user_permissions",
                ),
            },
        ),
        (_("Important dates"), {"fields": ("last_login", "date_joined")}),
    )
    add_fieldsets = (
        (
            None,
            {
                "classes": ("wide",),
                "fields": ("email", "password1", "password2"),
            },
        ),
    )
    list_display = ("email", "first_name", "last_name", "is_staff")
    ordering = ("-is_staff",)
    readonly_fields=('last_login', 'date_joined')

Then, run the command below. *This must be the 1st migration to database when customizing User model in this way otherwise there is error according to my experiments and the doc so before you develop your Django project, you must first create custom User model:

python manage.py makemigrations && python manage.py migrate

Then, run the command below:

python manage.py createsuperuser

Then, run the command below:

python manage.py runserver 0.0.0.0:8000

Then, open the url below:

http://localhost:8000/admin/login/

Finally, you can log in with email and password as shown below:

enter image description here

And, this is Add custom user page as shown below:

enter image description here

Dauntless answered 28/5, 2022 at 4:17 Comment(0)
C
2

You should customize ModelBackend class. My simple code:

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

And in settings.py file, add:

AUTHENTICATION_BACKENDS = ['path.to.class.YourBackend']
Chlor answered 17/3, 2017 at 3:55 Comment(1)
Update your code to include request parameter in authenticate method for django 2.1.1Vervet
D
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

And then in settings.py:

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

where articles is my django-app, backends.py is the python file inside my app and EmailAuthenticate is the authentication backend class inside my backends.py file

Demulsify answered 15/11, 2018 at 16:52 Comment(0)
D
1

All of these are horrendously complicated for what should be a simple problem.

Check that a user exists with that email, then get that user's username for the argument in Django's authenticate() method.

try:
    user = User.objects.get(email = request_dict['email'])
    user = authenticate(username = user.username, password = request_dict['password'])
except:
    return HttpResponse('User not found.', status = 400)
Dzungaria answered 7/4, 2023 at 1:29 Comment(0)
A
0

For Django 2

username = get_object_or_404(User, email=data["email"]).username
        user = authenticate(
            request, 
            username = username, 
            password = data["password"]
        )
        login(request, user)
Aquino answered 16/2, 2019 at 2:57 Comment(0)
L
0

Authentication with Email For 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')
Literality answered 19/8, 2019 at 4:29 Comment(0)
P
0

If You created Custom database, from there if you want to validate your email id and password.

  1. Fetch the Email id and Password with models.objects.value_list('db_columnname').filter(db_emailname=textbox email)

2.assign in list fetched object_query_list

3.Convert List to String

Ex :

  1. Take the Html Email_id and Password Values in Views.py

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

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

  2. Fetch the Email id and password from the database

    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. Take the Email id and password values in the list from the Query value set

    Email_Value = Email[0]

    Password_Value=Password[0]

  4. Convert list to String

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

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

Finally your Login Condition

if (string_email==u_email and string_password ==u_pass)
Paronymous answered 30/12, 2019 at 7:14 Comment(0)
J
-1

Pretty simple. There is no need for any additional classes.

When you create and update a user with an email, just set the username field with the email.

That way when you authenticate the username field will be the same value of the email.

The code:

# 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)
Jeannettejeannie answered 16/7, 2020 at 20:51 Comment(2)
Please add some sample code to help demonstrate how your answer can help solve the problem.Bucentaur
@CasmanRidder Your answer will be deleted if you don't add additional info.Violante
S
-1

The default user model inherits/ Extends an Abstract class. The framework should be lenient to a certain amount of changes or alterations.

A simpler hack is to do the following: This is in a virtual environment

  1. Go to your django installation location and find the Lib folder
  2. navigate to django/contrib/auth/
  3. find and open the models.py file. Find the AbstractUser class line 315

LINE 336 on the email attribute add unique and set it to true

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

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
  1. Done, makemigrations & migrate

Do this at you own risk,

Sextuplet answered 6/1, 2021 at 23:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.