Search code examples
djangodjango-custom-user

Any Possibility to put condition on Password Required in Django Custom Auth?


I want the registered user to log in with the Email or PhoneNumber and the Password first. If the user forgot the Password then there should be the possibility to log in with OTP bypassing the Password which would be provided via SMS on the User Phone Number. So Is there any possibility to achieve that?

Here are official docs where the password field is always required. https://docs.djangoproject.com/en/4.0/topics/auth/customizing/#a-full-example I know we can change the username to the email or for a phone number if we want but how do we put the condition to login with Password/Random OTP. So how we can achieve that? a suggestion would be appreciated. Thanks


Solution

  • You can make your own CustomLoginBackend as

    from django.contrib.auth import get_user_model
    
    class CustomLoginBackend(object):
    
        def authenticate(self, request, email, password, otp):
            User = get_user_model()
            try:
                user = User.objects.using(db_name).get(email=email)
            except User.DoesNotExist:
                return None
            else:
                if password is not None:
                    if getattr(user, 'is_active', False) and  user.check_password(password):
                        return user
                else:
                    if getattr(user, 'is_active', False) and  user.otp == otp: #<-- otp included in user table
                       return user
            return None
    

    Then in your login views.

    from django.contrib.auth import authenticate, login
    from django.contrib import messages
    
    def login_view(request):
        if request.method == 'POST':
            email = request.POST.get('email', None)
            password = request.POST.get('password', None)
            otp = request.POST.get('otp', None)
    
            user = authenticate(request, email=email, password=password, otp=otp)
            
            if user is not None:
                login(request, user)
                # redirect to a success page
                return redirect('dashboard')
            else:
                if password is not None:
                    # return either email or password incorrect
                    messages.error(request, "Invalid Email or Password")
                    return redirect('login')
                else:
                    # return invalid otp
                    messages.error(request, "Invalid OTP")
                    return redirect('login')
    
            return render(request, 'login.html')
    

    And at last don't forgot to add AUTHENTICATION_BACKENDS in your settings.py as

    AUTHENTICATION_BACKENDS = ['path_to_your.CustomLoginBackend ',]