17

I would like to create an authentication backend that allows users to log_in only using their email (no username, no password).

Here is what I tried.

backends.py:

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

class EmailAuthBackend(object):    
    def authenticate(self, username=None, password=None):
        try:
            user = User.objects.get(email=username)
            if user:
                return user
        except User.DoesNotExist:
            return None 

settings.py:

  AUTHENTICATION_BACKENDS = (
       'path_to.backends.EmailAuthBackend',
       'django.contrib.auth.backends.ModelBackend',
      )

html:

   <form  method="post" action="{% url myproject.views.test %}">
    {% csrf_token %}

        <input type="text" name="email" value=""/>

    <button type="submit">Valider</button>

    </form>

view:

 def test(request):
    email = ''
    if 'email' in request.POST:
        email = request.POST.get('email')
        if not User.objects.filter(email=email):
            User.objects.create(email=email)
        user = authenticate(username=email)
        if user is not None:
            if user.is_active:
                auth_login(request, user)
    return HttpResponseRedirect(reverse('home'))

It doesn't work, the user is not authenticated. And I also have this error when I go to the /admin:

    AttributeError at /admin/logout/
    'EmailAuthBackend' object has no attribute 'get_user'

2 Answers 2

22

For each custom backend in Django, you need to specify the get_user function. See the documentation. The get_user implementation can simply use the existing User table, like you are:

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

The reason this is required is for situations where you'd need to fetch the User via its primary key from a different source.

Sign up to request clarification or add additional context in comments.

Comments

7

While Bartek's answer is the correct one I'll just provide an example of another way to solve the problem by inheriting the ModelBackend.

from django.contrib.auth.backends import ModelBackend

class EmailAuthBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user
        except ObjectDoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            User().set_password(password)

The get_user is already implemented by the ModelBackend and you get the permission methods along with it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.