如果表单仅包含提交按钮,则 Symfony3 CSRF 错误
Symfony3 CSRF error if form contains only submit buttons
简介
我正在使用Symfony v3.4
我正在尝试从数据库中删除一件商品。为此,我使用方法 described here。
简而言之 - 可以使用两个表单提交按钮来决定 - 要么:删除一个项目,要么 return 列出(通过重定向)。检查表单有效性后,可以知道按下了哪个按钮以满足需要。 (此方法不依赖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 %}
尝试直接在您的表单中添加 CSRF:
...
{{ form_row(form._token) }}
{{ form_end(form) }}
其实可以的!
(唯一不同的是,以这种方式呈现形式是 Twig 特有的,而不是 Symfony 特有的)
但是您呈现表单的方式实际上(我猜是错误的)说 twig 不呈现 除了 "delete" 和 [=34= 之外的其他字段].这就是找不到您的 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) }}
简介
我正在使用Symfony v3.4
我正在尝试从数据库中删除一件商品。为此,我使用方法 described here。
简而言之 - 可以使用两个表单提交按钮来决定 - 要么:删除一个项目,要么 return 列出(通过重定向)。检查表单有效性后,可以知道按下了哪个按钮以满足需要。 (此方法不依赖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 %}
尝试直接在您的表单中添加 CSRF:
...
{{ form_row(form._token) }}
{{ form_end(form) }}
其实可以的!
(唯一不同的是,以这种方式呈现形式是 Twig 特有的,而不是 Symfony 特有的)
但是您呈现表单的方式实际上(我猜是错误的)说 twig 不呈现 除了 "delete" 和 [=34= 之外的其他字段].这就是找不到您的 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) }}