在头部:
<Meta name="csrf-param" content="authenticity_token" /> <Meta name="csrf-token" content="some_token" />
在身体下面:
<form action="/someaction" method="post"> <input name="utf8" type="hidden" value="✓" /> <input type="hidden" name="_method" value="patch" /> <input type="hidden" name="authenticity_token" value="another_token" />
js调用需要csrf令牌.但为什么表单令牌与csrf令牌不同?表单提交中使用了哪两个令牌?
解决方法
首先,我们来看看这部分:
<Meta name="csrf-param" content="authenticity_token" /> <Meta name="csrf-token" content="some_token" />
此部分由方法csrf_meta_tags生成.从源代码中我们可以看到:
>< Meta name =“csrf-param”/>的“content”属性值取自request_forgery_protection_token,默认情况下为:authenticity_token.
>< Meta name =“csrf-token”/>的“content”属性值取自form_authenticity_token方法,其中令牌从会话中获取或生成.
现在让我们看一下这部分:
<input type="hidden" name="authenticity_token" value="another_token" />
从源头我们可以看到:
>此隐藏输入由extra_tags_for_form方法返回.
>在extra_tags_for_form内部调用token_tag方法.
> token_tag方法将标记作为参数.
> token_tag的令牌参数先前是从html_options_for_form方法中的form_tag方法的options参数中提取的.
因此,如果您没有在自定义令牌的选项中手动设置authenticity_token参数,并且不满足导致将令牌值设置为false的条件(将在下面提到),则token_tag方法将收到nil并调用相同的form_authenticity_token方法用于< Meta name =“csrf-token”/>标签创建.顺便说一下,为了填充输入的名称属性,它也使用request_forgery_protection_token,当< Meta name =“csrf-param”/>时使用.标签生成发生.
并且因为这一切都发生在同一个请求中,所以调用form_authenticity_token方法应该在两种情况下都返回相同的结果.
Which of the two tokens is used on form submission?
在表单提交时将使用来自隐藏输入的令牌.
来自< Meta />的令牌也可以使用,但仅当满足以下所有conditions(使token_tag方法的令牌参数设置为false)时才会满足:
>:remote => true应该在form_tag的选项中传递.
> embed_authenticity_token_in_remote_forms config设置为false.
> authenticity_token未在选项中传递.
But why is the form token different from the csrf token?
至于这个问题,可能是因为缓存而出现这个问题.或者,可能,如果您使用Turbolinks gem,它可能会导致此问题(如果您完全刷新页面并再次比较令牌,则可以检查此问题).有关Turbolinks问题的更多信息,请查看this question.