scheb / 2fa

Two-factor authentication for Symfony applications 🔐
MIT License
504 stars 75 forks source link

Custom form #206

Closed pdias closed 11 months ago

pdias commented 1 year ago

Bundle version: 6.9 Symfony version: 6.3 PHP version: 8.1.0

Description

I have 2fa configured and working correctly. Shows the following form during authentication:

image

But what I wanted was to change the form to use a form type (ex.: class TwofaType extends AbstractType) . To create an input like this:

image

My class for the form:

use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;

class TwofaType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add(
            'num1',
            NumberType::class,
            [
                'attr' => [
                    'class' => 'form-control form-control-alt form-control-lg twofa text-center px-0'
                ],
                'constraints' => [
                    new NotBlank(),
                    new Length(['min' => 1]),
                ],
            ]
        );

        $builder->add(
            'num2',
            NumberType::class,
            [
                'attr' => [
                    'class' => 'form-control form-control-alt form-control-lg twofa text-center px-0'
                ],
                'constraints' => [
                    new NotBlank(),
                    new Length(['min' => 1]),
                ],
            ]
        );

        $builder->add(
            'num3',
            NumberType::class,
            [
                'attr' => [
                    'class' => 'form-control form-control-alt form-control-lg twofa text-center px-0'
                ],
                'constraints' => [
                    new NotBlank(),
                    new Length(['min' => 1]),
                ],
            ]
        );

        $builder->add(
            'num4',
            NumberType::class,
            [
                'attr' => [
                    'class' => 'form-control form-control-alt form-control-lg twofa text-center px-0'
                ],
                'constraints' => [
                    new NotBlank(),
                    new Length(['min' => 1]),
                ],
            ]
        );

        $builder->add(
            'num5',
            NumberType::class,
            [
                'attr' => [
                    'class' => 'form-control form-control-alt form-control-lg twofa text-center px-0'
                ],
                'constraints' => [
                    new NotBlank(),
                    new Length(['min' => 1]),
                ],
            ]
        );

        $builder->add(
            'num6',
            NumberType::class,
            [
                'attr' => [
                    'class' => 'form-control form-control-alt form-control-lg twofa text-center px-0'
                ],
                'constraints' => [
                    new NotBlank(),
                    new Length(['min' => 1]),
                ],
            ]
        );

        $builder->addEventListener(FormEvents::SUBMIT, [$this, 'submit']);
    }

    public function submit(FormEvent $event)
    {
        $twofa = $event->getData();

        if (!$twofa) {
            return;
        }

        $code = '';

        foreach ($twofa as $number) {
            $code .= $number;
        }

        $twofa['code'] = $code;
        $event->setData($twofa);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'translation_domain' => 'my.user',
        ]);
    }

    public function getName()
    {
        return $this->getBlockPrefix();
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix(): string
    {
        return 'my_user_2fa';
    }
}

I don't know if this is possible or if there is a simpler way to do it.

Thanks.

scheb commented 1 year ago

You can define a custom form render to completely customize the rendering of the form. An example for such a custom form renderer can be found here: https://symfony.com/bundles/SchebTwoFactorBundle/current/firewall_template.html (The presented use-case is a different one, but is shows how the technical implementation of a custom form renderer is done).


The bundle expects the value to be posted over in a single field, rather than 6 separate form fields. So your requirement of having 6 separate form fields will make things more complicated. The best way to do it is:

stale[bot] commented 11 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.