简体   繁体   English

如果表单仅包含提交按钮,Symfony3 CSRF错误

[英]Symfony3 CSRF error if form contains only submit buttons

Introduction 介绍

I am using Symfony v3.4 我正在使用Symfony v3.4

I am trying to delete an item of goods from database. 我正在尝试从数据库中删除商品。 In order to do so i am using approach described here . 为了做到这一点,我使用这里描述的方法。

In short - it is possible to use two form submit buttons to decide - either: delete an item or return to list (by redirect). 简而言之-可以使用两个表单提交按钮来决定-删除项目或返回列表(通过重定向)。 After checking form validity it is possible to know which button was pressed so it suites the needs. 在检查表单有效性之后,可以知道按下了哪个按钮,从而满足了需求。 (This approach does not rely on JavaScript). (这种方法不依赖JavaScript)。

For the purpose i created form with 2 differently named submit buttons (with no additional fields). 为此,我创建了带有2个不同名称的提交按钮的表单(没有其他字段)。 I create the form in controller and pass it to the view, it displays as expected. 我在控制器中创建表单并将其传递给视图,它按预期显示。

Problem 问题

Problem is - when i submit form it is not valid! 问题是-我提交表格时无效! The error is: The CSRF token is invalid. Please try to resubmit the form. 错误是: The CSRF token is invalid. Please try to resubmit the form. The CSRF token is invalid. Please try to resubmit the form. Resubmitting does not change a thing, form remains not valid... 重新提交不会改变任何事情,表格仍然无效...

I thought that Symfony Forms automatically handles CSRF token! 我认为Symfony Forms自动处理CSRF令牌! Does it not in this case? 在这种情况下不是吗? What am i missing? 我想念什么?

Question

What is the best practice in this situation? 在这种情况下,最佳做法是什么?

Profiler screen shot Profiler屏幕截图

在此处输入图片说明

Code

my FormType 我的FormType

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ReservationActionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('delete', SubmitType::class, array(
                'attr' => array('class' => 'btn btn-danger'),
                'label' => 'Yes, delete an item'
            ))
            ->add('return', SubmitType::class, array(
                'attr' => array('class' => 'btn btn-default'),
                'label' => 'No, return to list'
            ));
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            array(
                'csrf_protection' => true,
                'csrf_field_name' => '_token',
            )
        );
    }
}

my Controller 我的Controller

public function reservationDelete($reservation_id = 0, Request $request)
{
    // get $reservation that corresponds $reservation_id from database

    $form = $this->createForm(ReservationActionType::class);

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid())
    {
        if ($form->get('delete')->isClicked())
        {
            dump('replace this with item delete code');
        }
        else if ($form->get('return')->isClicked())
        {
            return $this->redirectToRoute('admin_reservations');
        }
    }

    return $this->render('admin/reservations_use_code.html.twig',
        [
            'reservation_id' => $reservation_id,
            'reservation' => $reservation,
            'form' => $form->createView()
        ]
    );
}

my template part where form resides 我的表单所在的template部分

{% if reservation['id'] is defined %}
    {{ form_start(form, {'attr': {'novalidate': 'novalidate', 'method': 'POST'}}) }}
        {{ form_widget(form.delete) }}
        {{ form_widget(form.return) }}
    {{ form_end(form) }}
{% endif %}

Try to add the CSRF in your form directly : 尝试直接在表单中添加CSRF:

   ...
   {{ form_row(form._token) }}
{{ form_end(form) }}

Actually, yes it can! 其实可以。

(With the small difference that rendering forms this way is specific to Twig, rather than Symfony) (区别在于这种方式形成的渲染特定于Twig,而不是Symfony)

But the way you render your form, you are actually (by mistake I guess) saying twig not to render other fields than "delete" and "return". 但是实际上,您渲染表格的方式(我猜是错误的)是说树枝不渲染 “删除”和“返回”以外的其他字段。 This is why your CSRF token is not found. 这就是为什么找不到您的CSRF令牌的原因。

Instead of rendering your fields manually, I would suggest you to use a theme ( https://symfony.com/doc/3.4/form/form_customization.html ) to customize your specific rows and fields. 我建议您使用主题( https://symfony.com/doc/3.4/form/form_customization.html )自定义特定的行和字段,而不是手动呈现字段。

Then you can just render your form in the following ways : 然后,您可以通过以下方式呈现表单:

{{ form(form) }}

To surcharge the form itself, rendering all fields automatically (including CSRF) : notice the difference between form_widget(form) (render all fields) and form_widget(form.my_field) (render "my_field" only) 要附加表单本身,自动渲染所有字段(包括CSRF):请注意form_widget(form) (渲染所有字段)和form_widget(form.my_field) (仅渲染“ my_field”)之间的区别

{{ form_start(form, { attr: { novalidate: true }}) }}
    {{ form_widget(form) }}
{{ form_end(form) }}

To surcharge a specific field without using theme (a bit heavier to write IMO), use form_rest(form) to render all the other fields (including CSRF) 要在不使用主题的情况下附加特定字段(编写IMO会比较form_rest(form) ),请使用form_rest(form)渲染所有其他字段(包括CSRF)

{{ form_start(form) }}
    {{ form_row(form.delete, { attr: { class: 'whatever' }}) }}
    {{ form_rest(form) }}
{{ form_end(form) }}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM