You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony3.4仅含提交按钮表单出现CSRF错误的技术问询

嘿,我在Symfony 3.4里处理过多提交按钮的表单场景,咱们一步步搞定这个CSRF错误问题。

问题根源分析

你遇到的CSRF错误,大概率是因为表单渲染时漏掉了CSRF Token字段——两个提交按钮本身不会携带CSRF Token,而Symfony默认会强制验证这个Token来防止跨站请求伪造。另外,如果处理请求时的逻辑顺序不对,也可能导致Token验证失败。

完整解决方案

下面是经过验证的代码示例,涵盖表单创建、模板渲染和控制器处理全流程:

1. 创建带双提交按钮的表单类型

首先定义表单类,明确开启CSRF保护(Symfony 3.4默认开启,但显式声明更稳妥),并给两个按钮设置唯一的name:

// src/AppBundle/Form/ProductDeleteFormType.php
namespace AppBundle\Form;

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

class ProductDeleteFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('delete', SubmitType::class, [
                'label' => '确认删除',
                'attr' => ['class' => 'btn btn-danger']
            ])
            ->add('back', SubmitType::class, [
                'label' => '返回列表',
                'attr' => ['class' => 'btn btn-default']
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            // 可选:指定Token标识,增强安全性
            'csrf_token_id' => 'product_delete_operation',
        ]);
    }
}

2. 控制器处理逻辑

在控制器中,一定要先调用handleRequest让Symfony自动处理CSRF验证,再判断哪个按钮被点击:

// src/AppBundle/Controller/ProductController.php
namespace AppBundle\Controller;

use AppBundle\Entity\Product;
use AppBundle\Form\ProductDeleteFormType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class ProductController extends Controller
{
    public function deleteAction(Request $request, Product $product)
    {
        $form = $this->createForm(ProductDeleteFormType::class);
        $form->handleRequest($request);

        if ($form->isSubmitted()) {
            // 先验证表单有效性(包含CSRF Token验证)
            if ($form->isValid()) {
                if ($form->get('delete')->isClicked()) {
                    // 执行删除操作
                    $em = $this->getDoctrine()->getManager();
                    $em->remove($product);
                    $em->flush();

                    $this->addFlash('success', '商品已成功删除');
                }
                // 无论点击哪个按钮,最终都返回列表页
                return $this->redirectToRoute('product_list');
            } else {
                // CSRF验证失败时的提示
                $this->addFlash('error', '请求无效,请重试');
                return $this->redirectToRoute('product_list');
            }
        }

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

3. Twig模板渲染

关键是要确保Symfony能渲染出隐藏的CSRF Token字段,最简单的方式是使用form_end(form)(它会自动调用form_rest输出所有未渲染的字段,包括Token):

{# app/Resources/views/product/delete.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h2>确认删除商品</h2>
    <p>你确定要删除商品 <strong>{{ product.name }}</strong> 吗?此操作不可撤销。</p>

    {{ form_start(form) }}
        {{ form_widget(form.delete) }}
        {{ form_widget(form.back) }}
    {{ form_end(form) }}
{% endblock %}
避坑要点
  • 绝对不能省略form_end(form)或form_rest(form):这两个方法会自动输出隐藏的CSRF Token字段,没有它Symfony会直接抛出CSRF错误。
  • 必须先调用$form->handleRequest($request):这个方法是Symfony处理表单数据、验证CSRF Token的核心步骤,跳过它直接判断按钮点击会导致验证失效。
  • 不要手动关闭CSRF保护:除非你有特殊业务场景,否则保留默认的CSRF保护是必要的安全措施。

内容的提问来源于stack exchange,提问作者Rikijs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:25:49