自动生成的 Symfony 6 注册表上显示“CSRF 令牌无效”

问题描述 投票:0回答:1

我正在尝试在我的 Symfony 6 项目中创建用户身份验证。我已完成所有设置 - 用户实体及其 Doctrine 数据库迁移、项目数据库及其所需的表、由

bin/console make:user-registration
自动生成的用户注册字段 - 但我总是收到以下错误:

The CSRF token is invalid. Please try resubmitting the form.

我已经尝试了几件事 - 从头开始,使用自动生成的默认的、未经编辑的用户实体,手动包含 CSRF 字段,使用自签名 SSL 证书,以防 HTTP 出现错误 - 没有任何效果。

我将添加代码片段,以防你们好心人需要检查它们(即使它们是自动生成的)。

/src/Controller/RegistrationController.php

<?php

namespace App\Controller;

use App\Entity\User;
use App\Form\RegistrationFormType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;

class RegistrationController extends AbstractController
{
    #[Route('/register', name: 'app_register')]
    public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response
    {
        $user = new User();
        $form = $this->createForm(RegistrationFormType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            // encode the plain password
            $user->setPassword(
                $userPasswordHasher->hashPassword(
                    $user,
                    $form->get('plainPassword')->getData()
                )
            );

            $entityManager->persist($user);
            $entityManager->flush();
            // do anything else you need here, like send an email

            return $this->redirectToRoute('_preview_error');
        }

        return $this->render('registration/register.html.twig', [
            'registrationForm' => $form->createView(),
        ]);
    }
}

src/Form/RegistrationFormType.php

<?php

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;

class RegistrationFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('username')
            ->add('agreeTerms', CheckboxType::class, [
                'mapped' => false,
                'constraints' => [
                    new IsTrue([
                        'message' => 'You should agree to our terms.',
                    ]),
                ],
            ])
            ->add('plainPassword', PasswordType::class, [
                // instead of being set onto the object directly,
                // this is read and encoded in the controller
                'mapped' => false,
                'attr' => ['autocomplete' => 'new-password'],
                'constraints' => [
                    new NotBlank([
                        'message' => 'Please enter a password',
                    ]),
                    new Length([
                        'min' => 6,
                        'minMessage' => 'Your password should be at least {{ limit }} characters',
                        // max length allowed by Symfony for security reasons
                        'max' => 4096,
                    ]),
                ],
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

模板/注册/register.html.twig

{% extends 'base.html.twig' %}

{% block title %}Register{% endblock %}

{% block body %}
    <h1>Register</h1>

    {{ form_errors(registrationForm) }}

    {{ form_start(registrationForm) }}
        {{ form_row(registrationForm.username, {
            icon: "icons/user.svg"
        }) }}
        {{ form_row(registrationForm.plainPassword, {
            label: 'Password'
        }) }}
        {{ form_row(registrationForm.agreeTerms) }}

        <button type="submit" class="btn">Register</button>
    {{ form_end(registrationForm) }}
{% endblock %}

am使用自定义表单主题,但这不会导致问题,特别是考虑到 CSRF 令牌仍然可以很好地传递到发送给用户的最终 HTML 中。

编译后的HTML表单:

<form method="post" name="registration_form">
  <div>
    <label class="block required text-gray-800" for="registration_form_username"
      >Username</label
    >
    <div
      class="bg-grey-950 border border-secondary-light fill-white flex flex-row focus-within:border-primary focus-within:outline-primary focus-within:ring-1 focus-within:ring-offset-1 focus-within:ring-primary-light placeholder-grey px-6 py-3 rounded shadow-md text-white w-full"
    >
      <div class="-ml-4 -my-1 fill-white flex icon items-center pr-2">
        <svg fill="currentColor" height="32" viewBox="0 0 256 256" width="32">
          <!-- SVG icon data here -->
        </svg>
      </div>
      <input name="username" type="text"
        required maxlength="90" 
        class="bg-transparent border-0 focus:border-transparent focus:ring-0 focus:ring-offset-0 outline-none p-0 w-full"
      />
    </div>
  </div>
  <div>
    <label for="registration_form_plainPassword"
      class="block required text-gray-800"
      >Password</label
    >
    <div
      class="bg-grey-950 border border-secondary-light fill-white flex flex-row focus-within:border-primary focus-within:outline-primary focus-within:ring-1 focus-within:ring-offset-1 focus-within:ring-primary-light placeholder-grey px-6 py-3 rounded shadow-md text-white w-full"
    >
      <div class="-ml-4 -my-1 fill-white flex icon items-center pr-2">
        <svg fill="currentColor" height="32" viewBox="0 0 256 256" width="32">
          <!-- SVG icon data here -->
        </svg>
      </div>
      <input name="plainPassword" type="password"
        required autocomplete="new-password"
        class="bg-transparent border-0 focus:border-transparent focus:ring-0 focus:ring-offset-0 outline-none p-0 w-full"
      />
    </div>
  </div>
  <div class="mb-6">
    <div class="inline-flex items-center">
      <input id="registration_form_agreeTerms" name="registration_form[agreeTerms]"
        type="checkbox" value="1" required
        class="mr-2"
      />
      <label for="registration_form_agreeTerms"
        class="block required text-gray-800"
        >Agree terms</label
      >
    </div>
  </div>
  <button class="btn" type="submit">Register</button>
  <div>
    <input name="_token" type="hidden"
      value="3b091c63ffd73f7851594efa3a99f8.XXbsDPuiFYQ0X7OklSp7vPxLO_BUr3GaUZhOCGwZEUc.JAycZ6jIbdJWDOf18mQKha8DfL8G9gL7CPQfXCZMYyMIEK4-ltVA6l8H9g"
    />
  </div>
</form>
symfony symfony-forms
1个回答
0
投票

嗯,看来这实际上是我的表单主题的错误。我忘记在我的块中添加 id 和 name 属性:

{% block form_widget_simple %} {# ...content here... #} <input id="{{ id }}" name="{{ full_name }}" type="{{ type }}" {# ...other attributes here... #} /> {# ...content here... #} {% endblock form_widget_simple %} {% block checkbox_widget %} <input id="{{ id }}" name="{{ full_name }}" type="radio" {# ...other attributes here... #} /> {% endblock checkbox_widget %} {% block radio_widget %} <input id="{{ id }}" name="{{ full_name }}" type="radio" {# ...other attributes here... #} /> {% endblock radio_widget %} {% block button_widget %} {# ...content here... #} <button id="{{ id }}" name="{{ full_name }}" type="{{ type }}" {# ...other attributes here... #} > {# ...content here... #} </button> {# ...content here... #} {% endblock button_widget %}
    
© www.soinside.com 2019 - 2024. All rights reserved.