[Django]-Allowing both email and username login in Django project

8๐Ÿ‘

You can create separate AuthenticationEmailBackend just for logging by email and add it to AUTHENTICATION_BACKENDS in settings. In this way different AUTHENTICATION_BACKENDS are used as alternatives if authentication fails for previous AUTHENTICATION_BACKENDS.

app/auth.py

from django.contrib.auth import get_user_model
from django.contrib.auth.models import User


class AuthenticationEmailBackend(object):
    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 getattr(user, 'is_active', False) and 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 = (
    "django.contrib.auth.backends.ModelBackend",
    ...
    "app.auth.AuthenticationEmailBackend",
)

If you leave default django.contrib.auth.backends.ModelBackend in a list users can login by either username or email.

๐Ÿ‘คKamil

5๐Ÿ‘

Seems request parameter is needed in authenticate method from Django 1.11:

def authenticate(self, request, username=None, password=None)

According to what is said in Django documentation.

๐Ÿ‘คgil

2๐Ÿ‘

A simple backend which allows you to login with either an email address or a username.

It should be combined with another backend for checking permissions:

settings.py:

AUTHENTICATION_BACKENDS = (
    'myproject.accounts.backends.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend' )

account/backends.py:

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

class EmailOrUsernameModelBackend(object):
    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, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

and for case-insensitive :

class EmailOrUsernameModelBackend(object):
    def authenticate(self, username=None, password=None):
        # user_model = get_user_model()
        if '@' in username:
            # kwargs = {'email': username}
            field = 'email'
        else:
            # kwargs = {'username': username}
            field = 'username'
        try:

            case_insensitive_username_field = '{}__iexact'.format(field)
            user = User._default_manager.get(**{case_insensitive_username_field: username})

            # user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None
๐Ÿ‘คevergreen

2๐Ÿ‘

For Django 3.0:

# myapp/backends.py

from django.contrib.auth.backends import BaseBackend

from .models import MyUser


class EmailAuthenticationBackend(BaseBackend):

def authenticate(self, request, **kwargs):
    email = kwargs['username'].lower()  # If you made email case insensitive add lower()
    password = kwargs['password']
    try:
        my_user = MyUser.objects.get(email=email)
    except MyUser.DoesNotExist:
        return None
    else:
        if my_user.is_active and my_user.check_password(password):
            return my_user
    return None

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

This works for Django 2.0 and probably previous versions:

# myapp/backends.py

from django.contrib.auth.backends import ModelBackend

from .models import MyUser


class EmailAuthenticationBackend(ModelBackend):

    def authenticate(self, request, **kwargs):
        email = kwargs['username']
        password = kwargs['password']
        try:
            my_user = MyUser.objects.get(email=email)
        except MyUser.DoesNotExist:
            return None
        else:
            if my_user.is_active and my_user.check_password(password):
                return my_user
        return None

(Not sure if it is a good idea to extend the ModelBackend, you can crete your own class)

And then, for both versions:

# settings.py

AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",
    "myapp.backends.EmailAuthenticationBackend",
]
๐Ÿ‘คj4n7

0๐Ÿ‘

in models.py

class UserDet(models.Model):
       email = models.EmailField(max_length=20)
 
       userName = models.CharField(max_length=20) 

in views.py

def user_login(request):
    response_data={}
    if request.session.has_key('login_id'):  #If user already logedin send to dashboard else check userid and password
        return render(request, '/dashboard.html')
    else:
        if request.method == 'POST':  # If request method is post then only process request
            #print('here in login')
            try:

                username = request.POST.get('username')
                password = request.POST.get('pass')

                if '@' in username: #check for email
                    try:
                         
                        for u in UserDet.objects.filter(email=username):
                            #username=u['userName']
                            
                            username=u.userName
                    except:
                        response_data['code']=1000
                        response_data['status']='fail'
                        return HttpResponse(json.dumps(response_data), content_type="application/json")

                if not request.POST.get('rememberme', None):  # check user select the remember me or not if yes then create session that expire after long time
                    #print('seeing it 0')
                    request.session.set_expiry(0)
                 
                
                user = authenticate(username=username, password=password) # Check user exist or not
                
                if user:  #if user exist then
                    if user.is_active: #check user is active or not if active then successfully loged in else send error
                        login(request,user)
                        
                        update_last_login(None, user)
                        request.session['login_id'] = user.id
                        response_data['code']=800
                        response_data['status']='success'
                        return HttpResponse(json.dumps(response_data), content_type="application/json")
                        #return render(request, '/dashboard.html')
                    else:
                        response_data['code']=900  #Error for User is not active
                        response_data['status']='fail'
                        return HttpResponse(json.dumps(response_data), content_type="application/json")
                        #return HttpResponse("Your account was inactive.")
                else: #Error or Invalid username or password
                    #print("Someone tried to login and failed.")
                    #print("They used username: {} and password: {}".format(username,password))
                    response_data['code']=1000
                    response_data['status']='fail'
                    return HttpResponse(json.dumps(response_data), content_type="application/json")
            
            except:
                response_data['code']=1001
                response_data['status']='fail'
                return HttpResponse(json.dumps(response_data), content_type="application/json")
        else: #Return to index
                return redirect('/', {})


 

  
๐Ÿ‘คSumesh Sheoran

Leave a comment