Allowing both email and username login in django p

2020-02-26 13:24发布

I'm creating a django project for a school, and there are three main kinds of users - parents, teachers, and students. For parents and teachers, I would like them to login using email (they are currently using email logins for a legacy system).

However, for students, I would like them to login using the conventional username approach (since young kids don't have emails). Is this possible to do in Django or is there only one User Authentication model allowed?

标签: python django
3条回答
女痞
2楼-- · 2020-02-26 14:01

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.

查看更多
我想做一个坏孩纸
3楼-- · 2020-02-26 14:06

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.

查看更多
相关推荐>>
4楼-- · 2020-02-26 14:13

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
查看更多
登录 后发表回答