Как сделать двухфакторную авторизацию через email?

В Django существует несколько способов реализации двухфакторной авторизации через электронную почту. В этом ответе я расскажу о самом распространенном и простом способе, который включает в себя следующие шаги:

1. Установка и настройка пакета Django Two-Factor Authentication:

Для начала установим пакет с помощью pip:

   pip install django-two-factor-auth

Затем добавим его в список установленных приложений в настройках Django:

   INSTALLED_APPS = [
       ...
       'django_otp',
       'django_otp.plugins.otp_totp',
       'django_otp.plugins.otp_hotp',
       'two_factor',
       ...
   ]

Также добавим два middleware-класса в список MIDDLEWARE:

   MIDDLEWARE = [
       ...
       'two_factor.middleware.threadlocals.ThreadLocals',
       'two_factor.middleware.threadlocals.DeviceVerificationMiddleware',
       ...
   ]

После этого можно выполнить миграции:

   python manage.py migrate

2. Настройка двухэтапной аутентификации для пользователя:

Для пользователя, которому нужно включить двухфакторную авторизацию, необходимо включить эту опцию через административную панель Django или программно. Если вы хотите включить двухфакторную аутентификацию для пользователя программно, вы можете сделать это следующим образом:

   from two_factor.models import PhoneDevice

   def enable_two_factor_auth(user):
       device = PhoneDevice.objects.create(name='My Phone', user=user, method='call')
       device.generate_challenge()
       device.save()

После этого пользователь должен ввести свой номер телефона и подтвердить его. Затем он получит телефонный звонок с кодом авторизации.

3. Создание и отправка одноразового кода подтверждения на почту:

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

Создайте функцию, которая будет генерировать этот код и отправлять его на почту пользователя.

   from django.core.mail import send_mail
   from django.utils.crypto import get_random_string

   def send_otp_code(user):
       code = get_random_string(length=6, allowed_chars='0123456789')
       subject = 'Ваш одноразовый код подтверждения'
       message = f'Ваш код подтверждения: {code}'
       send_mail(subject, message, '[email protected]', [user.email])
       return code

4. Проверка кода подтверждения:

После отправки кода подтверждения на почту пользователя, вам необходимо реализовать проверку этого кода при попытке входа в систему.

   from django.http import HttpResponse
   from two_factor.views.utils import default_device

   def login(request):
       if request.method == 'POST':
           email = request.POST['email']
           otp_code = request.POST['otp_code']

           user = User.objects.get(email=email)
           
           if user.check_otp(otp_code):
               default_device(user=user, remember=True)
               return HttpResponse('Вы успешно вошли в систему с двухфакторной аутентификацией.')
           else:
               return HttpResponse('Неправильный код подтверждения.')
       else:
           return render(request, 'login.html')

Обратите внимание, что вам нужно будет добавить соответствующий шаблон login.html и учесть защиту от перебора кодов.

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