[Django]-Django Multiple Authentication Backend for one project

49👍

You can have multiple authentication backends. Just set the AUTHENTICATION_BACKENDS in settings.py of your Django project to list the backend implementations you want to use. For example I often use a combination of OpenID authentication and the standard Django authentication, like this in my settings.py:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'django_openid_auth.auth.OpenIDBackend',
    )

In this example Django will first try to authenticate using django.contrib.auth.backends.ModelBackend, which is the default backend of Django. If that fails, then it moves on to the next backend, django_openid_auth.auth.OpenIDBackend.

Note that your custom backends must be at a path visible by Django. In this example I have to add django_openid_auth to INSTALLED_APPS, otherwise Django won’t be able to import it and use it as a backend.

Also read the relevant documentation, it’s very nicely written, easy to understand:
https://docs.djangoproject.com/en/dev/topics/auth/customizing/

👤janos

9👍

I’ve been through this problem before. This is the code I used.

This is the authentication backend at the api/backend.py

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 this is my settings.py

AUTHENTICATION_BACKENDS = (
    'api.backend.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)

This code will enable you to use email to authenticate the default Django user even in Django admin.

2👍

Using multiple backend authentications is as simple as pie. You just need to understand the workflow of Django apps.

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.Backend1',
    'django_openid_auth.auth.Backend2',
    )

For example you have the following two backends defined. Django will first go to the first backend and you just need to put some logic in that backend so that, if its not related to that backend it get forwarded to the other backend or returned without any results. In case of no results django will automatically shift the request from first backend to the second and if available third one.
I spend a lot of time on this and found out that it was not that complex.

1👍

Using Multiple AUTHENTICATION BACKENDS is very easy,
you just need to add this to settings.py

AUTHENTICATION_BACKENDS = (
    'social_core.backends.open_id.OpenIdAuth',
    'social_core.backends.google.GoogleOpenId',
    'social_core.backends.google.GoogleOAuth2',
    'social_core.backends.google.GoogleOAuth',
    'social_core.backends.facebook.FacebookOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)

and this may create a problem at signup page so add a login argument in your signup view in views.py file like this
login(request, user, backend=’django.contrib.auth.backends.ModelBackend’)

def signup_view(request):
    if request.method=='POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user=form.save()
            login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            return redirect('home')

0👍

Done a little safety and reassemble for code. cause provided solutions wasn’t perfectly matching necessary.

my version for the previous: https://stackoverflow.com/a/17078818/14972653
with my addition and @M.Void comment:

This is the authentication backend at the api/backend.py

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.core.validators import validate_email

user_model = get_user_model()


class EmailOrUsernameModelBackend(ModelBackend):
    """EmailOrUsernameModelBackend - UsernameOrEmail custom authentication backend 
    with email or username validation on same field

    provides case insensitive validation of username and email

    BEWARE - if you allow users to register two usernames in differren cases like: Alex and alex - there would be error.

    still uses ModelBackend so provides permissions and is_active validation
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(user_model.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            validate_email(username)
        except ValidationError as e:
            kwargs = {'username__iexact': username}  # remove __iexact to make it case sensitive
        else:
            kwargs = {'email__iexact': username}  # remove __iexact to make it case sensitive
        try:
            user = user_model.objects.get(**kwargs)
        except user_model.DoesNotExist:
            return None
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

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

and of course add it to your authentication backends:

AUTHENTICATION_BACKENDS = (
    'api.backend.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)

👤agriev

Leave a comment