Как настроить кастомные Authentication Backends в Django?

Ответ

В Django Authentication Backends — это классы, которые определяют, как пользователи аутентифицируются. Они позволяют расширять или полностью заменять стандартный механизм аутентификации Django, что крайне полезно для интеграции с внешними системами (LDAP, OAuth) или реализации нестандартных методов входа (например, по email вместо username).

По умолчанию Django использует django.contrib.auth.backends.ModelBackend, который аутентифицирует пользователей по имени пользователя и паролю, используя модель User.

Создание кастомного бэкенда:

Для создания собственного бэкенда необходимо унаследоваться от django.contrib.auth.backends.BaseBackend и реализовать как минимум два метода:

  1. authenticate(self, request, **credentials): Принимает request (опционально) и учетные данные (например, username, password). Должен вернуть объект User при успешной аутентификации или None в противном случае.
  2. get_user(self, user_id): Принимает user_id и должен вернуть объект User, соответствующий этому ID, или None.

Пример кастомного бэкенда для аутентификации по email (вместо username):

# myapp/backends.py
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model

class EmailAuthBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        User = get_user_model()
        try:
            # Попытка найти пользователя по email (который передается как username)
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user # Возвращаем пользователя при успешной проверке пароля
        except User.DoesNotExist:
            # Пользователь с таким email не найден
            return None
        return None # В случае других ошибок или несовпадения пароля

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

Регистрация бэкенда в settings.py:

Чтобы Django использовал ваш кастомный бэкенд, его необходимо добавить в список AUTHENTICATION_BACKENDS в файле settings.py. Порядок имеет значение: Django будет перебирать бэкенды по порядку, пока один из них не вернет пользователя.

# settings.py
AUTHENTICATION_BACKENDS = [
    'myapp.backends.EmailAuthBackend',  # Ваш кастомный бэкенд
    'django.contrib.auth.backends.ModelBackend', # Стандартный бэкенд Django (можно оставить или удалить)
]

Почему это важно?

Кастомные бэкенды обеспечивают высокую гибкость в управлении аутентификацией. Они позволяют:

  • Использовать альтернативные поля для входа (например, email, номер телефона).
  • Интегрироваться с внешними системами аутентификации (LDAP, OAuth, SAML).
  • Реализовывать сложные логики проверки учетных данных, не изменяя стандартные модели Django.
  • Поддерживать несколько методов аутентификации одновременно.

Ответ 18+ 🔞

А, блядь, смотри-ка, что у нас тут! Django и его бэкенды аутентификации, ёпта! Это ж как раз тот случай, когда стандартный механизм — как тесные трусы: вроде и носить можно, но если жопу побрил — уже не комфортно.

Вот смотри, по умолчанию Django использует ModelBackend. Это такой классический сторож-алкаш на проходной: «Пароль? Логин? Проходи». Работает через модель User, по username и паролю. Скучно, предсказуемо, но своё дело делает.

Но что, если тебе надо, чтобы люди заходили по почте? Или через какую-нибудь древнюю конторскую LDAP-систему, которая ещё на Windows 95 работает? Вот тут-то и начинается магия кастомных бэкендов, блядь!

Как сваять свой собственный, блядь, бэкенд?

Надо отнаследоваться от django.contrib.auth.backends.BaseBackend и запилить два метода. Не один, не три, а именно два, ёпта! Иначе — пиздец, ничего не заработает.

  1. authenticate(self, request, **credentials) — это главный шлюха-проверяльщик. Сюда прилетает request (может, а может и нет, похуй) и кучка учётных данных. Твоя задача — поковыряться в них, понять, свой ли это человек, и если свой — вернуть объект User. Если чужой — плюнуть и вернуть None.
  2. get_user(self, user_id) — это уже вспомогательный кореш. Ему скармливают user_id, а он должен, блядь, выдать юзера с таким айдишником. Или None, если такого не нашлось. Всё просто, как три копейки.

Вот тебе живой пример, блядь! Допустим, мы хотим пускать народ по email, а не по username. Смотри, как это выглядит:

# myapp/backends.py
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model

class EmailAuthBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        User = get_user_model()
        try:
            # Секрет в том, что 'username' — это просто имя аргумента, ёпта!
            # Мы можем передать туда что угодно. Ищем юзера по email.
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user  # Ура, наш человек! Пароль сошёлся!
        except User.DoesNotExist:
            # А такого email у нас в базе нет, блядь. Иди нахуй.
            return None
        return None  # На всякий пожарный, если пароль не прошёл.

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

Видишь? Всё гениально и просто. Никакой ебалы мозга.

Но это ещё не всё, ёбана! Надо этот шедевр ещё и прописать в настройках, иначе Django про него нихуя не узнает. Лезем в settings.py:

# settings.py
AUTHENTICATION_BACKENDS = [
    'myapp.backends.EmailAuthBackend',  # Наш красавец, идёт первым!
    'django.contrib.auth.backends.ModelBackend', # Стандартный, на подхвате.
]

Заметь, порядок — это пиздец как важно! Django будет тыкаться в бэкенды по списку, сверху вниз. Как только один скажет «Да, это наш!» и вернёт юзера — остальные даже не запустятся. Поэтому свой ставим выше.

А нахуя это всё, спросишь? Да затем, что это даёт тебе овердохуища гибкости! Можно:

  • Пускать людей по номеру телефона, по отпечатку пальца, по рисунку радужки глаза, ёпта!
  • Цепляться к корпоративному LDAP, где логины выглядят как CN=Иванов, И.И.,OU=ОтделБухгалтерии,DC=контора,DC=local.
  • Делать вход через OAuth от Гугла, ВК, Гитхаба — да через что угодно!
  • И всё это — без переписывания ядра Django и без чувства глубокого стыда.

Короче, кастомные бэкенды — это как запасной ключ от квартиры, где деньги лежат. Стандартный сломался — а у тебя свой, блядь, железный, всегда под рукой.