Редактирование формы входа в django

#python #django #two-factor-authentication

#python #django #двухфакторная аутентификация

Вопрос:

Я запускаю пример приложения django из этой библиотеки, вот весь код.

Я хотел бы добавить часть входа в это приложение, я хочу добавить больше полей в представление входа в систему, но я действительно не понимаю, как это сделать, потому что приложение не имеет собственного представления, но оно просто вызывает собственное представление входа в модуль. Но что, если я хотел бы использовать эту библиотеку для своего собственного проекта? Буду ли я вынужден использовать их представление входа в систему? Как я могу ее отредактировать?

Вот представление входа, которое в примере вызывается для обработки аутентификации:

core.py

 @class_view_decorator(sensitive_post_parameters())
@class_view_decorator(never_cache)
class LoginView(IdempotentSessionWizardView):
    """
    View for handling the login process, including OTP verification.
    The login process is composed like a wizard. The first step asks for the
    user's credentials. If the credentials are correct, the wizard proceeds to
    the OTP verification step. If the user has a default OTP device configured,
    that device is asked to generate a token (send sms / call phone) and the
    user is asked to provide the generated token. The backup devices are also
    listed, allowing the user to select a backup device for verification.
    """
    template_name = 'two_factor/core/login.html'
    form_list = (
        ('auth', AuthenticationForm),
        ('token', AuthenticationTokenForm),
        ('backup', BackupTokenForm),
    )
    idempotent_dict = {
        'token': False,
        'backup': False,
    }

    def has_token_step(self):
        return default_device(self.get_user())

    def has_backup_step(self):
        return default_device(self.get_user()) and 
            'token' not in self.storage.validated_step_data

    condition_dict = {
        'token': has_token_step,
        'backup': has_backup_step,
    }
    redirect_field_name = REDIRECT_FIELD_NAME

    def __init__(self, **kwargs):
        super(LoginView, self).__init__(**kwargs)
        self.user_cache = None
        self.device_cache = None

    def post(self, *args, **kwargs):
        """
        The user can select a particular device to challenge, being the backup
        devices added to the account.
        """
        # Generating a challenge doesn't require to validate the form.
        if 'challenge_device' in self.request.POST:
            return self.render_goto_step('token')

        return super(LoginView, self).post(*args, **kwargs)

    def done(self, form_list, **kwargs):
        """
        Login the user and redirect to the desired page.
        """
        login(self.request, self.get_user())

        redirect_to = self.request.POST.get(
            self.redirect_field_name,
            self.request.GET.get(self.redirect_field_name, '')
        )

        if not is_safe_url(url=redirect_to, allowed_hosts=[self.request.get_host()]):
            redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)

        device = getattr(self.get_user(), 'otp_device', None)
        if device:
            signals.user_verified.send(sender=__name__, request=self.request,
                                       user=self.get_user(), device=device)
        return redirect(redirect_to)

    def get_form_kwargs(self, step=None):
        """
        AuthenticationTokenForm requires the user kwarg.
        """
        if step == 'auth':
            return {
                'request': self.request
            }
        if step in ('token', 'backup'):
            return {
                'user': self.get_user(),
                'initial_device': self.get_device(step),
            }
        return {}

    def get_device(self, step=None):
        """
        Returns the OTP device selected by the user, or his default device.
        """
        if not self.device_cache:
            challenge_device_id = self.request.POST.get('challenge_device', None)
            if challenge_device_id:
                for device in backup_phones(self.get_user()):
                    if device.persistent_id == challenge_device_id:
                        self.device_cache = device
                        break
            if step == 'backup':
                try:
                    self.device_cache = self.get_user().staticdevice_set.get(name='backup')
                except StaticDevice.DoesNotExist:
                    pass
            if not self.device_cache:
                self.device_cache = default_device(self.get_user())
        return self.device_cache

    def render(self, form=None, **kwargs):
        """
        If the user selected a device, ask the device to generate a challenge;
        either making a phone call or sending a text message.
        """
        if self.steps.current == 'token':
            self.get_device().generate_challenge()
        return super(LoginView, self).render(form, **kwargs)

    def get_user(self):
        """
        Returns the user authenticated by the AuthenticationForm. Returns False
        if not a valid user; see also issue #65.
        """
        if not self.user_cache:
            form_obj = self.get_form(step='auth',
                                     data=self.storage.get_step_data('auth'))
            self.user_cache = form_obj.is_valid() and form_obj.user_cache
        return self.user_cache

    def get_context_data(self, form, **kwargs):
        """
        Adds user's default and backup OTP devices to the context.
        """
        context = super(LoginView, self).get_context_data(form, **kwargs)
        if self.steps.current == 'token':
            context['device'] = self.get_device()
            context['other_devices'] = [
                phone for phone in backup_phones(self.get_user())
                if phone != self.get_device()]
            try:
                context['backup_tokens'] = self.get_user().staticdevice_set
                    .get(name='backup').token_set.count()
            except StaticDevice.DoesNotExist:
                context['backup_tokens'] = 0

        if getattr(settings, 'LOGOUT_REDIRECT_URL', None):
            context['cancel_url'] = resolve_url(settings.LOGOUT_REDIRECT_URL)
        elif getattr(settings, 'LOGOUT_URL', None):
            warnings.warn(
                "LOGOUT_URL has been replaced by LOGOUT_REDIRECT_URL, please "
                "review the URL and update your settings.",
                DeprecationWarning)
            context['cancel_url'] = resolve_url(settings.LOGOUT_URL)
        return context
  

Ответ №1:

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

Шаг 1 Создайте свою собственную форму входа с дополнительными полями

Вы можете создать свою собственную форму входа, унаследовать от встроенной формы django или от формы, которую они используют для входа в систему. Добавьте в нее дополнительные поля.

 class YourLoginForm(AuthenticationForm):
    pass
    # your extra fields and functionality here 
  

Шаг 2 Унаследуйте представление входа в систему из пакета и используйте свою форму

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

 from TWO_FACTOR_AUTU import LoginView

class YourLoginView(LoginView):
    form_list = (
        ('auth', YourLoginForm),
        ('token', AuthenticationTokenForm),
        ('backup', BackupTokenForm),
    )
  

Используйте это представление с соответствующей маршрутизацией для обработки аутентификации.
Надеюсь, это поможет

Комментарии:

1. Привет! Прошу прощения за вопросы новичков, но я довольно новичок в Django. Прямо сейчас у меня уже есть форма входа, созданная мной, но проблема в том, что я не знаю, как интегрировать в нее всю часть 2fa, вот почему я задал этот вопрос. Было бы сложнее интегрировать 2fa в мое собственное представление входа в систему или было бы лучше добавить дополнительные поля в их собственное представление? И можете ли вы сказать мне, куда я должен поместить те 2 части кода, которые вы упомянули? В моем проекте? И в каких файлах? Опять же, извините, но я новичок в этом. Большое спасибо за вашу помощь 🙂

2. Мы вам очень рады. Я предлагаю вам использовать их представление аутентификации в вашей форме, а не использовать ваше представление с их двухфакторной функциональностью. Это было бы относительно просто. Вы можете поместить этот код в любое ваше приложение, сформировать в forms.py и просмотреть в views.py . Просто позаботьтесь о функциональности входа в форме. Он должен обрабатывать аутентификацию и аннулировать себя, если имя пользователя и пароль неверны.

3. Хорошо! Таким образом, второй блок кода должен отображаться в моем собственном представлении входа, в то время как первый на forms.py ? Спасибо!