我用AJAX从视图向控制器发送数据我得到了这个错误:
警告:无法验证CSRF令牌的真实性
我想我必须发送带有数据的令牌 .
有谁知道我该怎么做?
Edit: My solution
我通过将以下代码放在AJAX帖子中来完成此操作:
headers: { 'X-Transaction': 'POST Example', 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') },
你应该做这个:
确保布局中包含 <%= csrf_meta_tag %>
<%= csrf_meta_tag %>
将 beforeSend 添加到所有ajax请求以设置 Headers ,如下所示:
beforeSend
$.ajax({ url: 'YOUR URL HERE', type: 'POST', beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))}, data: 'someData=' + someData, success: function(response) { $('#someDiv').html(response); } });
要在所有请求中发送令牌,您可以使用:
$.ajaxSetup({ headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') } });
实现此目的的最佳方法实际上只是使用 <%= form_authenticity_token.to_s %> 直接在rails代码中打印出令牌 . 你不需要使用javascript来搜索dom中的csrf令牌,正如其他帖子所提到的那样 . 只需添加 Headers 选项,如下所示;
<%= form_authenticity_token.to_s %>
$.ajax({ type: 'post', data: $(this).sortable('serialize'), headers: { 'X-CSRF-Token': '<%= form_authenticity_token.to_s %>' }, complete: function(request){}, url: "<%= sort_widget_images_path(@widget) %>" })
如果我没记错的话,你必须在表单中添加以下代码,以解决这个问题:
<%= token_tag(nil) %>
不要忘记参数 .
从较旧的应用程序升级到rails 3.1,包括csrf元标记仍然没有解决它 . 在rubyonrails.org博客上,他们提供了一些升级提示,特别是这一行jquery应该放在你的布局的head部分:
$(document).ajaxSend(function(e, xhr, options) { var token = $("meta[name='csrf-token']").attr("content"); xhr.setRequestHeader("X-CSRF-Token", token); });
取自这篇博文:http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails .
在我的情况下,会话正在重置每个ajax请求 . 添加上面的代码解决了这个问题 .
确实最简单的方法 . 不要在改变 Headers 时烦恼 .
确保你有:
<%= csrf_meta_tag %> in your layouts/application.html.erb
只做一个隐藏的输入字段,如下所示:
<input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>"/>
或者如果你想要一个jQuery ajax帖子:
$.ajax({ type: 'POST', url: "<%= someregistration_path %>", data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" }, error: function( xhr ){ alert("ERROR ON SUBMIT"); }, success: function( data ){ //data response can contain what we want here... console.log("SUCCESS, data="+data); } });
添加 beforeSend 以在ajax请求中包含csrf-token以设置标头 . 只有 post 请求才需要这样做 .
post
rails/jquery-ujs 中提供了读取csrf-token的代码,因此最简单的方法是使用它,如下所示:
rails/jquery-ujs
$.ajax({ url: url, method: 'post', beforeSend: $.rails.CSRFProtection, data: { // ... } })
我只是想把这个链接到这里,因为这篇文章有你想要的大部分答案,而且它也很有趣
http://www.kalzumeus.com/2011/11/17/i-saw-an-extremely-subtle-bug-today-and-i-just-have-to-tell-someone/
此处的最高投票答案是正确的,但如果您正在执行 cross-domain 请求将无效,因为除非您明确告诉jQuery传递会话cookie,否则会话将不可用 . 以下是如何做到这一点:
$.ajax({ url: url, type: 'POST', beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')) }, xhrFields: { withCredentials: true } });
您可以像下面一样全局编写它 .
普通JS:
$(function(){ $('#loader').hide() $(document).ajaxStart(function() { $('#loader').show(); }) $(document).ajaxError(function() { alert("Something went wrong...") $('#loader').hide(); }) $(document).ajaxStop(function() { $('#loader').hide(); }); $.ajaxSetup({ beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))} }); });
咖啡脚本:
$('#loader').hide() $(document).ajaxStart -> $('#loader').show() $(document).ajaxError -> alert("Something went wrong...") $('#loader').hide() $(document).ajaxStop -> $('#loader').hide() $.ajaxSetup { beforeSend: (xhr) -> xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')) }
哎呀..
我错过了我的application.js中的以下行
//= require jquery_ujs
我替换它和它的工作..
=======更新=========
5年后,我回来了同样的错误,现在我有全新的 Rails 5.1.6 ,我又找到了这篇文章 . 就像生活圈 .
现在问题是: Rails 5.1 默认删除了对jquery和jquery_ujs的支持,并添加了
//= require rails-ujs in application.js
它做了以下事情:
强制确认各种动作的对话框;
从超链接发出非GET请求;
使表单或超链接与Ajax异步提交数据;
已提交按钮在表单提交时自动禁用,以防止双击 . (来自:https://github.com/rails/rails-ujs/tree/master)
但为什么不包括ajax请求的csrf令牌?如果有人详细了解这一点,请评论我 . 我很感激 .
无论如何,我在我的自定义js文件中添加了以下内容以使其工作(感谢其他答案,以帮助我达到此代码):
$( document ).ready(function() { $.ajaxSetup({ headers: { 'X-CSRF-Token': Rails.csrfToken() } }); ---- ---- });
如果您使用javascript和jQuery在表单中生成令牌,则可以:
<input name="authenticity_token" type="hidden" value="<%= $('meta[name=csrf-token]').attr('content') %>" />
显然,您需要在Ruby布局中使用 <%= csrf_meta_tag %> .
如果您没有使用jQuery并使用类似fetch API的请求,您可以使用以下内容来获取 csrf-token :
csrf-token
document.querySelector('meta[name="csrf-token"]').getAttribute('content')
fetch('/users', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')}, credentials: 'same-origin', body: JSON.stringify( { id: 1, name: 'some user' } ) }) .then(function(data) { console.log('request succeeded with JSON response', data) }).catch(function(error) { console.log('request failed', error) })
使用jquery.csrf(https://github.com/swordray/jquery.csrf) .
$ yarn add jquery.csrf
//= require jquery.csrf
source 'https://rails-assets.org' do gem 'rails-assets-jquery.csrf' end
(function($) { $(document).ajaxSend(function(e, xhr, options) { var token = $('meta[name="csrf-token"]').attr('content'); if (token) xhr.setRequestHeader('X-CSRF-Token', token); }); })(jQuery);
对于那些需要非jQuery答案的人,您可以简单地添加以下内容:
xmlhttp.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
这里有一个非常简单的例子:
xmlhttp.open("POST","example.html",true); xmlhttp.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); xmlhttp.send();
如果有人需要与Uploadify和Rails 3.2相关的帮助(就像我在Google上搜索这篇文章时那样),这个示例应用可能会有所帮助:https://github.com/n0ne/Uploadify-Carrierwave-Rails-3.2.3/blob/master/app/views/pictures/index.html.erb
还要检查此应用中的控制器解决方案
我正在使用Rails 4.2.4并且无法理解我为什么会这样做:
Can't verify CSRF token authenticity
我在布局中:
<%= csrf_meta_tags %>
在控制器中:
protect_from_forgery with: :exception
调用 tcpdump -A -s 999 -i lo port 3000 是显示正在设置的标头(尽管不需要使用 ajaxSetup 设置标头 - 它已经完成):
tcpdump -A -s 999 -i lo port 3000
ajaxSetup
X-CSRF-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest DNT: 1 Content-Length: 125 authenticity_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
最后它失败了,因为我关闭了cookie . 如果没有启用cookie,CSRF将无法工作,因此如果您看到此错误,这是另一个可能的原因 .
几天我一直在努力解决这个问题 . 任何GET调用都正常工作,但所有PUT都会生成“无法验证CSRF令牌真实性”错误 . 我的网站工作正常,直到我向nginx添加了SSL证书 .
我终于在我的nginx设置中偶然发现了这条缺失的行:
location @puma { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Forwarded-Proto https; # Needed to avoid 'WARNING: Can't verify CSRF token authenticity' proxy_pass http://puma; }
添加缺失行“proxy_set_header X-Forwarded-Proto https;”后,我的所有CSRF令牌错误都会退出 .
希望这可以帮助那些也正在撞墙的人 . 哈哈
17 回答
你应该做这个:
确保布局中包含
<%= csrf_meta_tag %>
将
beforeSend
添加到所有ajax请求以设置 Headers ,如下所示:要在所有请求中发送令牌,您可以使用:
实现此目的的最佳方法实际上只是使用
<%= form_authenticity_token.to_s %>
直接在rails代码中打印出令牌 . 你不需要使用javascript来搜索dom中的csrf令牌,正如其他帖子所提到的那样 . 只需添加 Headers 选项,如下所示;如果我没记错的话,你必须在表单中添加以下代码,以解决这个问题:
不要忘记参数 .
从较旧的应用程序升级到rails 3.1,包括csrf元标记仍然没有解决它 . 在rubyonrails.org博客上,他们提供了一些升级提示,特别是这一行jquery应该放在你的布局的head部分:
取自这篇博文:http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails .
在我的情况下,会话正在重置每个ajax请求 . 添加上面的代码解决了这个问题 .
确实最简单的方法 . 不要在改变 Headers 时烦恼 .
确保你有:
只做一个隐藏的输入字段,如下所示:
或者如果你想要一个jQuery ajax帖子:
确保布局中包含
<%= csrf_meta_tag %>
添加
beforeSend
以在ajax请求中包含csrf-token以设置标头 . 只有post
请求才需要这样做 .rails/jquery-ujs
中提供了读取csrf-token的代码,因此最简单的方法是使用它,如下所示:我只是想把这个链接到这里,因为这篇文章有你想要的大部分答案,而且它也很有趣
http://www.kalzumeus.com/2011/11/17/i-saw-an-extremely-subtle-bug-today-and-i-just-have-to-tell-someone/
此处的最高投票答案是正确的,但如果您正在执行 cross-domain 请求将无效,因为除非您明确告诉jQuery传递会话cookie,否则会话将不可用 . 以下是如何做到这一点:
您可以像下面一样全局编写它 .
普通JS:
咖啡脚本:
哎呀..
我错过了我的application.js中的以下行
我替换它和它的工作..
=======更新=========
5年后,我回来了同样的错误,现在我有全新的 Rails 5.1.6 ,我又找到了这篇文章 . 就像生活圈 .
现在问题是: Rails 5.1 默认删除了对jquery和jquery_ujs的支持,并添加了
它做了以下事情:
强制确认各种动作的对话框;
从超链接发出非GET请求;
使表单或超链接与Ajax异步提交数据;
已提交按钮在表单提交时自动禁用,以防止双击 . (来自:https://github.com/rails/rails-ujs/tree/master)
但为什么不包括ajax请求的csrf令牌?如果有人详细了解这一点,请评论我 . 我很感激 .
无论如何,我在我的自定义js文件中添加了以下内容以使其工作(感谢其他答案,以帮助我达到此代码):
如果您使用javascript和jQuery在表单中生成令牌,则可以:
显然,您需要在Ruby布局中使用
<%= csrf_meta_tag %>
.如果您没有使用jQuery并使用类似fetch API的请求,您可以使用以下内容来获取
csrf-token
:document.querySelector('meta[name="csrf-token"]').getAttribute('content')
使用jquery.csrf(https://github.com/swordray/jquery.csrf) .
对于那些需要非jQuery答案的人,您可以简单地添加以下内容:
这里有一个非常简单的例子:
如果有人需要与Uploadify和Rails 3.2相关的帮助(就像我在Google上搜索这篇文章时那样),这个示例应用可能会有所帮助:https://github.com/n0ne/Uploadify-Carrierwave-Rails-3.2.3/blob/master/app/views/pictures/index.html.erb
还要检查此应用中的控制器解决方案
我正在使用Rails 4.2.4并且无法理解我为什么会这样做:
我在布局中:
在控制器中:
调用
tcpdump -A -s 999 -i lo port 3000
是显示正在设置的标头(尽管不需要使用ajaxSetup
设置标头 - 它已经完成):最后它失败了,因为我关闭了cookie . 如果没有启用cookie,CSRF将无法工作,因此如果您看到此错误,这是另一个可能的原因 .
几天我一直在努力解决这个问题 . 任何GET调用都正常工作,但所有PUT都会生成“无法验证CSRF令牌真实性”错误 . 我的网站工作正常,直到我向nginx添加了SSL证书 .
我终于在我的nginx设置中偶然发现了这条缺失的行:
添加缺失行“proxy_set_header X-Forwarded-Proto https;”后,我的所有CSRF令牌错误都会退出 .
希望这可以帮助那些也正在撞墙的人 . 哈哈