Советы для Джанго

Добавление пользовательской аутентификации в Django

Повестка дня

Нам необходимо добавить пользовательский бэкенд аутентификации в наш проект Django.

Механизм аутентификации по умолчанию в Django требует, чтобы пользователь предоставил имя пользователя и пароль.

Рассмотрим сценарий, в котором вы создаете банковское приложение. У каждого клиента есть customer_id. Возможно, вы захотите поддержать аутентификацию клиента с помощью имени пользователя и customer_id.

Основы

Наиболее распространенный способ в приложении Django показывает два поля, а именно имя пользователя и пароль в форме входа. Эти значения передаются в Django authenticate() из представления.

authenticate выполняет классы аутентификации, указанные в settings.AUTHENTICATION_BACKENDS.

По умолчанию AUTHENTICATION_BACKENDS выглядит так:

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

Мы хотим разрешить аутентификацию с customer_id, при этом поддерживая механизм аутентификации по умолчанию, где пользователь может аутентифицироваться, используя имя пользователя.

Настройка

Предположим, у нас есть модель под названием Customer.

# customers/models.py

class Customer(BaseModel):
    customer_id = models.CharField(max_length=10)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    address = models.TextField()
    city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)

    objects = CustomerManager()

    def __str__(self):
        return self.customer_id

Нам нужно будет добавить класс аутентификации, назовем его CustomerBackend.

Это будет выглядеть следующим образом:

# customers/backends.py

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User

from customers.models import Customer

class CustomerBackend(ModelBackend):

    def authenticate(self, request, **kwargs):
        customer_id = kwargs['username']
        password = kwargs['password']
        try:
            customer = Customer.objects.get(customer_id=customer_id)
            if customer.user.check_password(password) is True:
                return customer.user
        except Customer.DoesNotExist:
            pass

Форма и вид могут оставаться неизменными и сохранять имена полей в качестве имени пользователя и пароля. Нам нужно добавить CustomerBackend в AUTHENTICATION_BACKENDS.

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'customers.backends.CustomerBackend',
]

При этом пользователь сможет войти в систему либо под своим именем пользователя, либо под своим customer_id.

Поделитесь с другими: