环顾四周,我找不到解决这个问题的方法。只有在通过 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/