Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticate user using email and password

Tags:

django

I have a form that only allow users to login via username . I decided to only allow user to login via email instead of username.

First, this is not a duplication of any question relating to logging via email because in my scenario, I validate and authenticate the user in forms.py before he proceed to the final login in views so it give me the chance to raise an error for incorrect login passwords etc.

The issue i'm facing is I modified my forms.py to raise an error if the email doesn't exist which works but It wouldn't let the user login via his email.

 def LoginRequest(request):
     form = LoginForm(request.POST or None)    
     if request.POST and form.is_valid():
         user = form.login(request)
         if user:
             login(request, user)
             return HttpResponseRedirect(reverse('Hello'))

     return render(request, 'login.html',{'form': form})

This is my original code which only allow users to login via username

 class LoginForm(forms.Form):
     username = forms.CharField()
     password = forms.CharField(
        widget=forms.PasswordInput(render_value=False)
        )

     def clean(self):        
         username = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')
         user = authenticate(username=username, password=password)
         if not user or not user.is_active:
             raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
         return self.cleaned_data

     def login(self, request):
         username = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')
         user = authenticate(username=username, password=password)
         return user

This is my modified code which only allow users to login via email. I thought a lot about how I would do it but this is the best idea I came up with. Sorry it's a bit confusing. The problem is, it wouldn't let the user login. I don't understand why.

 class LoginForm(forms.Form):
     username = forms.CharField()
     password = forms.CharField(
            widget=forms.PasswordInput(render_value=False)
        )

     def clean(self):       
         user = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')

         if User.objects.filter(email=user).exists():
             password = self.cleaned_data.get('password')
             user = authenticate(username=user.username, password=password)
             if not user or not user.is_active:
                 raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
             return self.cleaned_data

     def login(self, request):
         username = self.cleaned_data.get('username')
         password = self.cleaned_data.get('password')
         user = authenticate(username=username, password=password)
         return user

Can someone please help me?

like image 548
JackRoster Avatar asked May 18 '13 15:05

JackRoster


People also ask

How do I authenticate my email address and password?

Enable Email/Password sign-in: In the Firebase console, open the Auth section. On the Sign in method tab, enable the Email/password sign-in method and click Save.

What is email link authentication?

This technique involves providing an authentication mechanism where the user can enter their email address, and they are sent an email with a link to click. When the user clicks the link in the email, they are directed back to the website and automatically logged in.

What is the proper way to deal with a password for authentication purposes?

Recent online security best practices suggest that users create passwords that are at least 8 characters (the ideal number is around 12 characters long) and use a combination of uppercase and lowercase letters, numbers, and symbols.

What type of authentication is a username and a password?

Password-based authentication Also known as knowledge-based authentication, password-based authentication relies on a username and password or PIN. The most common authentication method, anyone who has logged in to a computer knows how to use a password.


3 Answers

As dougis pointed out you are trying to authenticate the user using email, But authenticate function authenticates user based on username and password. So here is the trick to authenticate the user using email (complete working form):

from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User
from django import forms
from django.contrib.auth import authenticate

class LoginForm(forms.Form):
    email = forms.CharField()
    password = forms.CharField(
        widget=forms.PasswordInput(render_value=False)
        )

    def clean(self):
        user = self.authenticate_via_email()
        if not user:
            raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
        else:
            self.user = user
        return self.cleaned_data

    def authenticate_user(self):
        return authenticate(
            username=self.user.username,
            password=self.cleaned_data['password'])

    def authenticate_via_email(self):
        """
            Authenticate user using email.
            Returns user object if authenticated else None
        """
        email = self.cleaned_data['email']
        if email:
            try:
                user = User.objects.get(email__iexact=email)
                if user.check_password(self.cleaned_data['password']):
                    return user
            except ObjectDoesNotExist:
                pass
        return None

views.py

def LoginRequest(request):
    form = LoginForm(request.POST or None)    
    if request.method == 'POST' and form.is_valid():
        user = form.authenticate_user()
        login(request, user)
        return HttpResponseRedirect(reverse('Hello'))

    return render(request, 'login.html',{'form': form})
like image 175
Aamir Rind Avatar answered Oct 13 '22 08:10

Aamir Rind


You can also write a custom backend:

# yourapp.backends.py    
from django.contrib.auth.models import User


class EmailOrUsernameModelBackend(object):
    """ Authenticate user by username or email """
    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
            else:
                return None
        except User.DoesNotExist:
            return None

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

Now add your backend to settings.py:

AUTHENTICATION_BACKENDS = (
    'yourapp.backends.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)
like image 36
bogs Avatar answered Oct 13 '22 07:10

bogs


Looks like you are testing against 2 different fields. You look for the user against email

if User.objects.filter(email=user).exists():

but then validate against username

user = authenticate(username=user, password=password)

If you are using the email address the auth line should be

user = authenticate(email=user, password=password)
like image 37
dougis Avatar answered Oct 13 '22 07:10

dougis