_token is present on the POST data but form fails with error: "The CSRF token is invalid. Please try to resubmit the form"
_token is present on the POST data but form fails with error: "The CSRF token is invalid. Please try to resubmit the form"
我知道这个话题已经在 SO 中讨论过多次,但我已经检查了很多话题 none 似乎和我的很像,到目前为止我所测试的并没有解决我的问题。首先,我将 Symfony 3.2.4 与 PHP 7.1.2.
一起使用
我的控制器中有以下代码:
class QuoteController extends Controller
{
/**
* @Route("/quote/register")
*/
public function registerAction()
{
$entity = new Quote();
$form = $this->createForm(QuoteType::class, $entity);
return $this->render(
'QuoteBundle:Quote:register.html.twig',
['entity' => $entity, 'form' => $form->createView()]
);
}
/**
* @Route("/quote/save", name="save-quote")
*/
public function saveAction()
{
$entity = new Quote();
$form = $this->createForm(QuoteType::class, $entity);
$request = Request::createFromGlobals();
$form->handleRequest($request);
if ($form->isValid()) {
dump($form->getData());
} else {
dump($_POST);
dump($form->getErrors());
}
die();
}
}
这是我的 QuoteType
的样子:
class QuoteType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('schneider_quote_id')
->add('agreement_number')
->add('quote_creation_source')
->add('quote_status')
->add('distributor_id')
->add('start_date', DateType::class)
->add('end_date', DateType::class)
->add('save', SubmitType::class, ['label' => 'Create Post']);
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'data_class' => Quote::class,
]);
}
/**
* @return string
*/
public function getName()
{
return 'quote';
}
}
最后这就是我的模板寄存器的样子:
{% block body %}
{{ form_start(form, {'action': path('save-quote'), 'method': 'POST'}) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{{ form_row(form._token) }}
{{ form_end(form) }}
{% endblock %}
但是当我发送表格时出现错误:
The CSRF token is invalid. Please try to resubmit the form.
如果您注意到我 dump()
表单错误中的 $_POST
数据,这就是结果:
dump($_POST);
array:1 [▼
"quote" => array:9 [▼
"schneider_quote_id" => "100"
"agreement_number" => "100"
"quote_creation_source" => "sdasdasd"
"quote_status" => "sadsad"
"distributor_id" => "2"
"start_date" => array:3 [▶]
"end_date" => array:3 [▶]
"save" => ""
"_token" => "bSuU7h7rDR-_FkEGZ3zS60OtIofs_1bAi-J-YdCtxlM"
]
]
dump($form->getErrors());
FormErrorIterator {#32 ▼
-form: Form {#672 ▼
-config: FormBuilder {#673 ▶}
-parent: null
-children: OrderedHashMap {#674 ▶}
-errors: array:1 [▼
0 => FormError {#625 ▶}
]
-submitted: true
-clickedButton: SubmitButton {#787 ▶}
-modelData: Quote {#444 ▶}
-normData: Quote {#444 ▶}
-viewData: Quote {#444 ▶}
-extraData: []
-transformationFailure: null
-defaultDataSet: true
-lockSetData: false
}
-errors: array:1 [▼
0 => FormError {#625 ▼
-message: "The CSRF token is invalid. Please try to resubmit the form."
#messageTemplate: "The CSRF token is invalid. Please try to resubmit the form."
#messageParameters: []
#messagePluralization: null
-cause: null
-origin: Form {#672}
}
]
}
问题是,如果 _token
出现在 POST 上,为什么 Symfony 无法正确读取数据?
我已经阅读了 CSRF Protection from The Form Components 的文档,但我现在很困惑,也许 Symfony 3 中的情况发生了变化,但我不知道。我的控制器|表单中是否需要这段代码?
use Symfony\Component\Form\Forms;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
use Symfony\Component\Security\Csrf\CsrfTokenManager;
// create a Session object from the HttpFoundation component
$session = new Session();
$csrfGenerator = new UriSafeTokenGenerator();
$csrfStorage = new SessionTokenStorage($session);
$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);
$formFactory = Forms::createFormFactoryBuilder()
// ...
->addExtension(new CsrfExtension($csrfManager))
->getFormFactory();
为什么我在这里不见了?
折腾了好几次终于找到问题出在哪里了。这就是我的 session
部分在 config.yml
:
中的样子
session:
storage_id: session.storage.php_bridge
handler_id: ~
save_path: ~
将上面的配置更改为这个:
session:
handler_id: session.handler.native_file
save_path: ~
显然 ~
根本没有设置默认值 handler_id
。
我知道这个话题已经在 SO 中讨论过多次,但我已经检查了很多话题 none 似乎和我的很像,到目前为止我所测试的并没有解决我的问题。首先,我将 Symfony 3.2.4 与 PHP 7.1.2.
一起使用我的控制器中有以下代码:
class QuoteController extends Controller
{
/**
* @Route("/quote/register")
*/
public function registerAction()
{
$entity = new Quote();
$form = $this->createForm(QuoteType::class, $entity);
return $this->render(
'QuoteBundle:Quote:register.html.twig',
['entity' => $entity, 'form' => $form->createView()]
);
}
/**
* @Route("/quote/save", name="save-quote")
*/
public function saveAction()
{
$entity = new Quote();
$form = $this->createForm(QuoteType::class, $entity);
$request = Request::createFromGlobals();
$form->handleRequest($request);
if ($form->isValid()) {
dump($form->getData());
} else {
dump($_POST);
dump($form->getErrors());
}
die();
}
}
这是我的 QuoteType
的样子:
class QuoteType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('schneider_quote_id')
->add('agreement_number')
->add('quote_creation_source')
->add('quote_status')
->add('distributor_id')
->add('start_date', DateType::class)
->add('end_date', DateType::class)
->add('save', SubmitType::class, ['label' => 'Create Post']);
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'data_class' => Quote::class,
]);
}
/**
* @return string
*/
public function getName()
{
return 'quote';
}
}
最后这就是我的模板寄存器的样子:
{% block body %}
{{ form_start(form, {'action': path('save-quote'), 'method': 'POST'}) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{{ form_row(form._token) }}
{{ form_end(form) }}
{% endblock %}
但是当我发送表格时出现错误:
The CSRF token is invalid. Please try to resubmit the form.
如果您注意到我 dump()
表单错误中的 $_POST
数据,这就是结果:
dump($_POST);
array:1 [▼
"quote" => array:9 [▼
"schneider_quote_id" => "100"
"agreement_number" => "100"
"quote_creation_source" => "sdasdasd"
"quote_status" => "sadsad"
"distributor_id" => "2"
"start_date" => array:3 [▶]
"end_date" => array:3 [▶]
"save" => ""
"_token" => "bSuU7h7rDR-_FkEGZ3zS60OtIofs_1bAi-J-YdCtxlM"
]
]
dump($form->getErrors());
FormErrorIterator {#32 ▼
-form: Form {#672 ▼
-config: FormBuilder {#673 ▶}
-parent: null
-children: OrderedHashMap {#674 ▶}
-errors: array:1 [▼
0 => FormError {#625 ▶}
]
-submitted: true
-clickedButton: SubmitButton {#787 ▶}
-modelData: Quote {#444 ▶}
-normData: Quote {#444 ▶}
-viewData: Quote {#444 ▶}
-extraData: []
-transformationFailure: null
-defaultDataSet: true
-lockSetData: false
}
-errors: array:1 [▼
0 => FormError {#625 ▼
-message: "The CSRF token is invalid. Please try to resubmit the form."
#messageTemplate: "The CSRF token is invalid. Please try to resubmit the form."
#messageParameters: []
#messagePluralization: null
-cause: null
-origin: Form {#672}
}
]
}
问题是,如果 _token
出现在 POST 上,为什么 Symfony 无法正确读取数据?
我已经阅读了 CSRF Protection from The Form Components 的文档,但我现在很困惑,也许 Symfony 3 中的情况发生了变化,但我不知道。我的控制器|表单中是否需要这段代码?
use Symfony\Component\Form\Forms;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
use Symfony\Component\Security\Csrf\CsrfTokenManager;
// create a Session object from the HttpFoundation component
$session = new Session();
$csrfGenerator = new UriSafeTokenGenerator();
$csrfStorage = new SessionTokenStorage($session);
$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);
$formFactory = Forms::createFormFactoryBuilder()
// ...
->addExtension(new CsrfExtension($csrfManager))
->getFormFactory();
为什么我在这里不见了?
折腾了好几次终于找到问题出在哪里了。这就是我的 session
部分在 config.yml
:
session:
storage_id: session.storage.php_bridge
handler_id: ~
save_path: ~
将上面的配置更改为这个:
session:
handler_id: session.handler.native_file
save_path: ~
显然 ~
根本没有设置默认值 handler_id
。