javascript - Symfony 3 - CSRF token 仅在使用 AJAX 提交时无效

标签 javascript php jquery ajax symfony

环顾四周,我找不到解决这个问题的方法。只有在通过 Ajax 提交时,我才会收到以下错误。这意味着我事先已经以常规的 Symfony 方式提交了表单,没有任何问题。

The CSRF token is invalid. Please try to resubmit the form.

什么有效:

  • 常规表单提交,即不使用 Ajax
  • 我使用 Ajax 检查 $_POST 是否正确填充,包括 CSFR token ,就在 Controller 端提交之前,如下所示:

$form->submit($request->request->get($form->getName('user')));

根据要求,查看下面的输出

var_dump($request->request->get($form->getName('user')));

array(8) { 
["name"]=> string(9) "fafdffafa" 
["avatar"]=> string(9) "dfafffafa" 
["cityId"]=> string(1) "6" 
["phone"]=> string(14) "33434343434344" 
["email"]=> array(2) { 
      ["first"]=> string(22) "myemail@gmail.com" 
      ["second"]=> string(22) "myemail@gmail.com" } 
["plainPassword"]=> array(2) { 
      ["first"]=> string(8) "senha444" 
      ["second"]=> string(8) "senha444" } 
["blogSubs"]=> string(1) "1" 
["_token"]=> string(43) "hLhyoRxVYmJ_FWK0FqXmiiEYZMZ77fDAWvxCZMXCtxw" }

只是为了确认如果我只是注释掉下面的 javascript 提交将有效并且实体将被保留。

这是同一个 var_dump,这次是为了正常工作。

array(9) { 
["name"]=> string(12) "dfdfdfdfafaf" 
["avatar"]=> string(13) "dfdfdfdafdafa" 
["cityId"]=> string(1) "8" 
["phone"]=> string(16) "3343434343343343" 
["email"]=> array(2) { 
    ["first"]=> string(22) "myemail@gmail.com" 
    ["second"]=> string(22) "myemail@gmail.com" }
["plainPassword"]=> array(2) { 
    ["first"]=> string(8) "senha444" 
    ["second"]=> string(8) "senha444" } 
["blogSubs"]=> string(1) "1" 
["save"]=> string(0) "" 
["_token"]=> string(43) "hLhyoRxVYmJ_FWK0FqXmiiEYZMZ77fDAWvxCZMXCtxw" }

这是Symfony生成的提交按钮,js序列化没有捕捉到。

<button type="submit" id="user_save" name="user[save]" class="btn-default btn">Créer mon compte</button>

表单(我跳过 $builder 表单,因为它似乎没有必要)

app/Resources/views/common/register.html.twig

{{ form_start(form, { 'attr': { 'id': 'signup_form' }}) }}
    <div class="contact input-group">
        {{ form_widget(form.name) }}
    </div>
    <div class="contact input-group">
        {{ form_widget(form.avatar) }}
        <span class="input-group-addon" id="info_avatar">
            <i class="fa fa-info"></i>
        </span>       
    </div>
    <div class="contact input-group">
        {{ form_widget(form.cityId) }}
    </div>
    <div class="contact input-group">
        {{ form_widget(form.phone) }}           
    </div>
    <div class="contact input-group">
        {{ form_widget(form.email) }}
    </div>
    <div class="contact input-group">
        {{ form_widget(form.plainPassword) }}
    </div>
    <div class="contact">
        {{ form_widget(form.blogSubs) }}
    </div>
    <div class="contact form-group ">
        {{ form_widget(form.save) }}
    </div>
{{ form_end(form) }} 

同一文件上的javascript:

<script>
    $('body').on('submit','#signup_form',function(event) {
        event.preventDefault();
        var str = $("#signup_form").serialize();
        $.ajax({
            url: "/inscription",
            type: "POST",
            dataType:"json",
            data: str,
            success: function (data) {
                            alert(data);
            }   
        });
    });
  </script>

和 Controller (在 SO 上找到了 getErrorMessages() 方法。)

/src/UsedBundle/Controller/RegistrationController.php

namespace UsedBundle\Controller;

use UsedBundle\Form\UserType;
use UsedBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;

class RegistrationController extends Controller
{
/**
 * @Route("/inscription", name="inscription")
 */
public function registerAction(Request $request)
{
    $user = new User();
    $form = $this->createForm(UserType::class, $user);

    if ($request->isMethod('POST')) {
        var_dump($_POST);
        $form->submit($request->request->get($form->getName('user')));
        if(!$form->isValid()){ 
            $errors = $this->getErrorMessages($form);
            var_dump($errors);
        }
        if ($form->isSubmitted() && $form->isValid()) {
            $password = $this->get('security.password_encoder')
                ->encodePassword($user, $user->getPlainPassword());
            $user->setPassword($password);
            $email = $user->getEmail();
            $user->setUserKey( $email );
            $user->setUserKeyTime();
            $user->setDateReg();
            $em = $this->getDoctrine()->getManager('used');
            $em->persist($user);
            $em->flush();
            return new JsonResponse(array('message' => 'Success!'));
        }
    }else{
        return $this->render(
            'common/register.html.twig',
            array('form' => $form->createView())
        );           
    }
}

protected function getErrorMessages($form) 
{
    $errors = array();
    foreach ($form->getErrors() as $key => $error) {
        $errors[] = $error->getMessage();
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = $this->getErrorMessages($child);
        }
    }

    return $errors;
} 
}

最佳答案

正如评论中所讨论的,您的问题的原因与不同的环境有关。如果您将标准 Symfony 项目与 app_dev.php 前端 Controller 一起使用,您的表单将使用 dev 环境的有效 csrf token 呈现。你的 javascript 代码

$.ajax({
    url: "/inscription",
    type: "POST",
    dataType:"json",
    data: str,
    success: function (data) {
                    alert(data);
    }   
});

不知道 Symfony 环境,所以 url /location 指向 prod 环境,导致 CSRF token 无效的错误消息。

要解决这个问题,您可以让您的前端代码知道 Symfony 路由,例如通过使用 FOSJsRoutingBundle .或者您可以为 dev 环境禁用 CSRF 保护:

# app/config/config_dev.yml
framework:
    csrf_protection: false

关于javascript - Symfony 3 - CSRF token 仅在使用 AJAX 提交时无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44709271/

相关文章:

javascript - 按顺序运行 Javascript 函数(一个接一个)

c# - 将 JSON 字符串转换为有意义的完整数据进行解析

php - 如何防止 PHP 中的 SQL 注入(inject)?

jquery - 两次调用 .each() 之间 'this' 会发生什么?

javascript - TypeScript 或 JS-如何将一个元素及其所有子元素选择到 HTMLCollection 中?

javascript - 尝试转义 JavaScript 正则表达式中的句点但失败

PHP内置网络服务器运行速度很慢

javascript - 如何正确将php mysql数据传递给ChartJs

javascript - 使用延迟加载自定义 pagerTemplate

javascript - 将 Chrome 中 keydown 上的 <div> 标记替换为 <br> 以实现 HTML contenteditable