var token = document.querySelector("Meta[name='csrf-token']").content; xhr.setRequestHeader("X-CSRF-Token",token);
并在我的控制器中插入一个断点,如下所示:
def verify_authenticity_token binding.pry super end
我已验证标头已设置:
[1] pry(#<MyController>)> request.headers => #<ActionDispatch::Http::Headers:0x007fb227cbf490 @env= {"CONTENT_LENGTH"=>"202",. . . # omitted headers . . . "HTTP_X_CSRF_TOKEN"=>"the-correct-token-from-Meta-tag",. . . }
我还尝试使用密钥authenticity_token(就像使用Rails表单一样)将令牌作为参数传递,并将X-CSRF-Param标记设置为匹配(来自Meta [name =“csrf-param”]).
但我仍然得到:
Can't verify CSRF token authenticity Completed 422 Unprocessable Entity in 14638ms ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken
有人见过这个吗?有什么可能导致这个问题的想法吗?
提前致谢!
编辑:
在marflar的回答的评论中讨论后,看起来令牌在请求发生时已经过期(通过与form_authenticity_token比较来测试).这让我更加困惑,因为在<%= csrf_Meta_tags%>中设置了令牌.当下一个请求进来时过期.有什么想法吗?
EDIT2:按照下面的marflar的建议,我将以下after_filter添加到我的app控制器:
def set_csrf_headers response.headers['X-CSRF-Param'] = request_forgery_protection_token.to_s response.headers['X-CSRF-Token'] = form_authenticity_token end
我在我的请求方法中更新了xhr.onload,如下所示:
namespace.request = = function (type,url,opts,callback) { // code omitted xhr.onload = function () { setCSRFHeaders(xhr); var res = {data: JSON.parse(xhr.response),status: xhr.status}; return callback.call(xhr,null,res); }; // code omitted } function setCSRFHeaders ( xhr ) { var csrf_param = xhr.getResponseHeader('X-CSRF-Param'); var csrf_token = xhr.getResponseHeader('X-CSRF-Token'); if (csrf_param) { document.querySelector("Meta[name='csrf-param']").content = csrf_param; } if (csrf_token) { document.querySelector("Meta[name='csrf-token']").content = csrf_token; } }
解决方法
> authenticity_token本身没有过期,所以在每次向服务器发出ajax请求后都不需要更新它
>不需要发送params [:authenticity_token]和header [‘x-csrf-token’],只需其中一个,rails将首先检查params,而不是header
>在页面刷新时,authenticity_token会有所不同,但没关系,因为每次使用一次填充生成它并且真正的csrf令牌(在服务器上)与时间无关
>会话中保存的真实csrf令牌[:_ csrf_token]
你可以看到令牌保持在会话中我的问题是我的会话在24小时后过期(可能是用户在页面上停留一天没有刷新)
如果用户通过cookie或其他令牌参数登录,则无论如何他都会获得新会话,并且会生成新的CSRF令牌,并且任何具有旧authenticity_token的请求都将无效.
因此,主要问题是会话,它已过期或重置.