【问题标题】:Symfony3 CSRF error if form contains only submit buttons如果表单仅包含提交按钮,则 Symfony3 CSRF 错误
【发布时间】:2018-02-10 21:38:38
【问题描述】:

简介

我正在使用Symfony v3.4

我正在尝试从数据库中删除一件商品。为此,我使用方法described here。

简而言之 - 可以使用两个表单提交按钮来决定 - 要么:删除项目或返回列表(通过重定向)。检查表单有效性后,可以知道按下了哪个按钮,从而满足需求。 (这种方法不依赖于 JavaScript)。

为此,我创建了带有 2 个不同名称的提交按钮(没有附加字段)的表单。我在控制器中创建表单并将其传递给视图,它按预期显示。

问题

问题是 - 当我提交表单时它是无效的!错误是:The CSRF token is invalid. Please try to resubmit the form. 重新提交不会改变任何事情,表单仍然无效...

我以为Symfony Forms 会自动处理 CSRF 令牌!在这种情况下不是吗?我错过了什么?

问题

在这种情况下,最佳做法是什么?

分析器屏幕截图

代码

我的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',
            )
        );
    }
}

我的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()
        ]
    );
}

我的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 %}

【问题讨论】:

    标签: php forms symfony validation csrf


    【解决方案1】:

    尝试直接在表单中添加 CSRF:

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

    【讨论】:

    • 谢谢,看起来成功了!所以这意味着如果确实没有字段,symfony form component 不会自动将_token 添加到表单中......
    【解决方案2】:

    其实可以的!

    (这种方式渲染表单的细微差别是特定于 Twig,而不是 Symfony)

    但是您呈现表单的方式实际上(我猜是错误的)说树枝不要呈现“删除”和“返回”以外的其他字段。这就是找不到您的 CSRF 令牌的原因。

    建议您使用主题 (https://symfony.com/doc/3.4/form/form_customization.html) 来自定义您的特定行和字段,而不是手动呈现您的字段。

    然后您可以通过以下方式呈现您的表单:

    {{ form(form) }}
    

    为了增加表单本身,自动渲染所有字段(包括 CSRF):注意form_widget(form)(渲染所有字段)和form_widget(form.my_field)(仅渲染“my_field”)之间的区别

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

    要在不使用主题的情况下对特定字段进行附加费(写 IMO 有点重),请使用 form_rest(form) 渲染所有其他字段(包括 CSRF)

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

    【讨论】:

    • 感谢您的回答。我的期望是(可能是错误的)当没有字段(仅提交按钮)并且不使用 {{ form_end(form, {'render_rest': false }) }} 时,表单应该包含 CSRF 令牌。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-18
    • 2017-08-01
    • 2017-10-10
    • 2023-04-01
    • 2021-06-12
    • 1970-01-01
    相关资源
    最近更新 更多