每次我尝试提交表单时都会收到这个错误消息:
CSRF令牌无效。请尝试重新提交表单
我的表单代码是:
<form novalidate action="{{path('signup_index')}}" method="post" {{form_enctype(form)}} role="form" class="form-horizontal">
<div class="form-group">
{{ form_label(form.email, 'Email', {'label_attr': {'class': 'col-md-1 control-label'}}) }}
{{ form_widget(form.email, {'attr': {'class': 'col-md-2'}}) }}
{{ form_errors(form.email) }}
</div>
<div class="form-group">
{{ form_label(form.nickname, 'Nickname', {'label_attr': {'class': 'col-md-1 control-label'}}) }}
{{ form_widget(form.nickname, {'attr':{'class': 'col-md-2'}}) }}
{{ form_errors(form.nickname, {'attr': {'class': 'col-md-3'}}) }}
</div>
<div class="form-group">
{{ form_label(form.password, 'password', {'label_attr': {'class': 'col-md-1 control-label'}}) }}
{{ form_widget(form.password, {'attr': {'class': 'col-md-2'}}) }}
{{ form_errors(form.password, {'attr': {'class': 'col-md-3'}}) }}
</div>
<div class="form-group">
{{ form_label(form.password_repeat, 'Repeat password', {'label_attr': {'class': 'col-md-1 control-label'}}) }}
{{ form_widget(form.password_repeat, {'attr':{'class': 'col-md-2'}}) }}
{{ form_errors(form.password_repeat, {'attr': {'class': 'col-md-3'}}) }}
</div>
<div class="form-group">
<div class="col-md-1 control-label">
<input type="submit" value="submit">
</div>
</div>
</form>
任何想法?
您需要在表单中添加_token
,即
{{ form_row(form._token) }}
到目前为止,您的表单缺少CSRF令牌字段。如果你使用twig form函数像form(form)
一样渲染你的表单,它会自动为你渲染CSRF令牌字段,但是你的代码显示你是用原始HTML像<form></form>
一样渲染你的表单,所以你必须手动渲染字段。
或者,在表单的结束标签前添加{{ form_rest(form) }}
。
根据docs
这将呈现尚未为给定对象呈现的所有字段的形式。这是一个好主意,总是有这个地方在您的表单因为它会为你渲染隐藏的字段并生成你忘记的字段为了呈现得更明显(因为它会为你呈现字段)。
form_rest(view, variables)
当你的表单有很多元素时,你也可以看到这个错误信息。
php.ini中出现问题的原因
; How many GET/POST/COOKIE input variables may be accepted
max_input_vars = 1000
问题是_token字段错过了PUT (GET)请求,所以你必须增加值。
同样,它涉及一个大文件。增加了
upload_max_filesize
选项将解决问题。
这是因为表单默认包含CSRF保护,在某些情况下这是不必要的。
您可以在getDefaultOptions
方法的表单类中禁用此CSRF保护,如:
// Other methods omitted
public function getDefaultOptions(array $options)
{
return array(
'csrf_protection' => false,
// Rest of options omitted
);
}
如果您不想禁用CSRF保护,那么您需要在表单中呈现CSRF保护字段。这可以通过在视图文件中使用{{ form_rest(form) }}
来实现,如下所示:
<form novalidate action="{{path('signup_index')}}" method="post" {{form_enctype(form)}} role="form" class="form-horizontal">
<!-- Code omitted -->
<div class="form-group">
<div class="col-md-1 control-label">
<input type="submit" value="submit">
</div>
</div>
{{ form_rest(form) }}
</form>
{{ form_rest(form) }}
呈现所有您没有手动输入的字段。
在</form>
标签前放置:
{{ form_rest(form) }}
它将自动插入其他重要的(隐藏的)输入。
我有一个奇怪的行为:清除浏览器缓存没有解决这个问题,但清除cookie(即PHP会话ID cookie)确实解决了这个问题。
这必须在检查了所有其他答案后完成,包括验证是否在隐藏的表单输入字段中具有令牌。
除了其他人的建议,如果会话存储不工作,您可以获得CSRF令牌错误。
在最近的一个案例中,我的一个同事将'session_prefix'更改为一个包含空格的值。
session_prefix: 'My Website'
这会破坏会话存储,这反过来意味着我的表单无法从会话中获取CSRF令牌。
如果您已经将表单从纯HTML转换为小文本,请确保没有遗漏删除结束的</form>
标记。愚蠢的错误,但我发现这可能是导致这个问题的原因。
当我得到这个错误时,我一开始不知道是怎么回事。我使用form_start()
和form_end()
来生成表单,所以我不应该显式地添加令牌与form_row(form._token)
,或使用form_rest()
来获得它。它应该已经被form_end()
自动添加了。
问题是,我正在使用的视图是我从纯HTML转换为小树枝的视图,我错过了删除关闭</form>
标签,所以不是:
{{ form_end(form) }}
我</form>
{{ form_end(form) }}
这实际上看起来像是可能抛出错误的东西,但显然它没有,所以当form_end()
输出form_rest()
时,表单已经关闭。表单实际生成的页面源如下所示:
<form>
<!-- all my form fields... -->
</form>
<input type="hidden" id="item__token" name="item[_token]" value="SQAOs1xIAL8REI0evGMjOsatLbo6uDzqBjVFfyD0PE4" />
</form>
显然,解决方案是删除额外的结束标签,也许喝更多的咖啡。
我最近有这个错误。原来我的cookie设置在config.yml中是不正确的。将cookie_path
和cookie_domain
设置添加到framework.session
中可以修复此问题。
我最近遇到了同样的问题,我的情况是这里没有提到的:
问题是我在localhost
域上测试它。我不知道为什么这是一个问题,但它开始工作后,我添加了localhost
的主机名别名到/etc/hosts
像这样:
127.0.0.1 foobar
在使用Apache和localhost
作为域时,会话可能有问题。如果有人能在评论中详细说明,我很乐意编辑这个答案,以包含更多细节。
如果你不想使用form_row或form_rest,只是想在你的小枝模板中访问_token的值。使用以下语句:
<input type="hidden" name="form[_token]" value="{{ form._token.vars.value }}" />
在我的情况下,我在实体中遇到了maxSize注释的问题,所以我将其从2048增加到20048。
/**
* @Assert'File(
* maxSize = "20048k",
* mimeTypes = {"application/pdf", "application/x-pdf"},
* mimeTypesMessage = "Please upload a valid PDF"
* )
*/
private $file;
希望这个答案有帮助!
我也遇到过类似的问题。在确保令牌字段实际呈现之后(请参阅已接受的答案),我检查了我的cookie。有2(!)cookie在我的Chrome浏览器的域,显然是因为我运行的应用程序在相同的域作为另一个应用程序,但有不同的端口(即mydomain.com设置原始cookie,而有bug的应用程序在mydomain.com:123上运行)现在很明显Chrome发送了错误的cookie,所以CSRF保护无法将令牌链接到正确的会话。
修复:清除所有cookie的问题域,确保你不运行多个应用程序在同一域不同的端口。
我有同样的错误,但在我的情况下,问题是我的应用程序使用多个一级域,而cookie使用一个。从config.yml
中的framework.session
中删除cookie_domain: ".%domain%"
会导致cookie默认为表单所在的任何域,这就解决了问题。
您需要记住CSRF令牌存储在会话中,因此由于无效的会话处理也可能发生此问题。如果你在本地主机上工作,检查例如,如果会话cookie域设置正确(在PHP中,在本地主机上它应该是空的)。
我在选项卡中打开同一网站的多个页面时遇到此错误。有些选项卡将无法提交。
我假设原因是每个请求在页面加载开始时读取会话,然后在页面完成加载后再次写入会话,覆盖其他页面加载的结果。
这似乎是一个问题,当使用bootstrap,除非你是呈现的形式{{form(form)}}。此外,问题似乎只发生在输入type="hidden"时。如果您检查带有表单的页面,您会发现隐藏的输入根本不是标记的一部分,或者它正在呈现,但由于某种原因没有提交。如上所述,添加{{form_rest(form)}}或像下面这样包装输入应该可以达到目的。
<div class="form-group">
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
</div>