Forms Symfony2防止多表单提交

Forms Symfony2防止多表单提交,forms,symfony,submit,csrf,Forms,Symfony,Submit,Csrf,我正在用Symfony2制作一张表格。由于{{form_rest(myform)},我有一些实体字段和一个正确呈现的csrf令牌 问题是: 用户填写表单并单击提交按钮(然后发布表单) 用户快速按下退出键 用户再次单击提交按钮(再次发布表单) 结果:在数据库中插入两次实体(表单绑定到实体) 这可以无限地发生 我认为使用CSRF令牌字段可以防止这种情况,但事实并非如此。那么,有没有办法通过Symfony框架在本地解决这个问题呢? 如果没有,存在什么可能性 提前谢谢你 CSRF令牌在会话期间不会更改,

我正在用Symfony2制作一张表格。由于
{{form_rest(myform)}
,我有一些实体字段和一个正确呈现的csrf令牌

问题是:

  • 用户填写表单并单击提交按钮(然后发布表单)
  • 用户快速按下退出键
  • 用户再次单击提交按钮(再次发布表单)
  • 结果:在数据库中插入两次实体(表单绑定到实体)

    这可以无限地发生

    我认为使用CSRF令牌字段可以防止这种情况,但事实并非如此。那么,有没有办法通过Symfony框架在本地解决这个问题呢? 如果没有,存在什么可能性


    提前谢谢你

    CSRF令牌在会话期间不会更改,因此您不能使用它来阻止多个表单提交

    您可以使用Javascript来解决字体端的这个问题,例如,请参见基本上在按下一次submit按钮后禁用它


    另请参见

    我不确定这是否是正确的方法,但您可以执行以下操作

    表单类型中,设置以下选项:

    对于Symfony<4,使用
    意图

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            // important part; unique key
            'intention'       => 'form_intention',
        ]);
    }
    
    对于Symfony>=4,使用csrf令牌id

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            // important part; unique key
            'csrf_token_id'   => 'form_intention',
        ]);
    }
    
    if ($form->isSubmitted()) {
        // refresh CSRF token (form_intention)
        $this->get("security.csrf.token_manager")->refreshToken("form_intention");
    }
    
    然后,在控制器操作中,您可以使用
    意图
    csrf\u令牌\u id
    执行类似操作:

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            // important part; unique key
            'csrf_token_id'   => 'form_intention',
        ]);
    }
    
    if ($form->isSubmitted()) {
        // refresh CSRF token (form_intention)
        $this->get("security.csrf.token_manager")->refreshToken("form_intention");
    }
    

    这可以防止重复提交给定表单。

    利用Symfony的另一种方法是在表单视图控制器上实现提交重定向到表单处理器控制器

    这通过一次接收表单值并在收到值后立即重定向用户来实现。 因此,如果操作被取消并多次重新提交或单击,则初始请求无法将用户重定向到表单处理器。有效地防止了多次提交数据,因为重定向响应会返回给用户,并且不会调用表单处理器

    使用状态代码307的重定向充当快捷方式,允许将整个请求传递给另一个控制器方法并保留请求方法类型和数据。同时,用户不会直观地注意到更改,也不会收到无效的CSRF令牌错误

    namespace AppBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    
    class DefaultController extends Controller
    {
    
        /**
         * @Route('/submit', name="submit")
         */
        public function submitAction(Request $request)
        {
           if ($request->isMethod($request::METHOD_POST)) {   
              return $this->redirectToRoute('process', ['request' => $request], 307);
           }
           //... form view
           $form = $this->createForm(FormType::class, $data, ['action' => $this->generateUrl('submit')]);
           $form->handleRequest($request);
           /** 
            * alternative to comparing the request method type above
            * if ($form->isSubmitted()) {
            *    return $this->redirectToRoute('process', ['request' => $request], 307);
            * }
            */
           return $this->render('::form_view', [
              'form' => $form->createView()
           ]);
        }
    
        /**
         * @Route('/process', name="process")
         */
        public function processAction(Request $request)
        {
           $form = $this->createForm(FormType::class, $data, ['action' => $this->generateUrl('submit')]);
           $form->handleRequest($request);
           if ($form->isSubmitted() && $form->isValid()) {
               //... process form
               $this->addFlash('success', 'Form Processed!');
               return $this->redirectToRoute('submit');
           }
    
           //... show form errors and allow resubmission
           return $this->render('::form_view', [
              'form' => $form->createView()
           ]);
        }
    }
    

    是的,它会像charme一样检测多次提交。但现在您必须处理invalidCSRF令牌。如果($form->isSubmitted()&&&!$form->isValid()){$submittedToken=$request->request->get('token');如果(!$this->isCsrfTokenValid('token_id',$submittedToken)){return$this->redirectoroute('home');//如果提交句柄完成,则执行您想要执行的操作。例如重定向}