使用 AJAX 向 Rails 发送真实性令牌的正确方法

问题描述 投票:0回答:10

这可以工作,但由于缺少真实性令牌而被停止:

$(".ajax-referral").click(function(){
  $.ajax({type: "POST", url: $(this).parent("form").attr("action"), dataType: "script"});
  return false;
});

所以我尝试像这样添加它:

$(".ajax-referral").click(function(){
  $.ajax({type: "POST", url: $(this).parent("form").attr("action") + "?&authenticity_token=" + AUTH_TOKEN, dataType: "script"});
  return false;
});

它正确地传递了 auth_token 作为参数,但似乎丢失了我表单的其余部分。

有什么方法可以同时发送有效的表单数据和真实性令牌吗?

这是一个 Rails 环境。我脑子里有这个。

= javascript_tag "var AUTH_TOKEN = '#{form_authenticity_token}';" if protect_against_forgery?

我尝试过的事情

1.

= hidden_field :authenticity_token, :value => form_authenticity_token

2.

$.ajax({type: "POST", url: $(this).parent("form").attr("action"), dataType: "script", authenticity_token: AUTH_TOKEN});

3.

// Always send the authenticity_token with ajax
$(document).ajaxSend(function(event, request, settings) {
    if ( settings.type != 'GET' ) {
        settings.data = (settings.data ? settings.data + "&" : "")
            + "authenticity_token=" + encodeURIComponent( AUTH_TOKEN );
    }
});
javascript jquery ruby-on-rails ajax authenticity-token
10个回答
34
投票

如果顶部有以下 ERB,则默认情况下此标记也已出现在 application.html.erb 布局文件头部的“meta”标记之一中:

<%= csrf_meta_tag %>

ERB 大致呈现为:

<meta content="abc123blahblahauthenticitytoken" name="csrf-token">

然后您可以通过以下代码使用 jQuery 来获取它:

var AUTH_TOKEN = $('meta[name=csrf-token]').attr('content');

33
投票

实际上,您正在读取表单的

action
属性并向其发送 post ajax 请求。要发送表单数据,您必须提交表单,或者您可以序列化表单数据并在 ajax 请求中发送,例如

$(".ajax-referral").click(function(){
  $.ajax({
      type: "POST", 
      url: $(this).parent("form").attr("action") + "?&authenticity_token=" + AUTH_TOKEN, 
      data:$(this).parent("form").serialize(),
      dataType: "script"
      });
  return false;
});

这样做将序列化您的表单数据并将其与ajax请求一起发送,并且真实性令牌已经通过查询字符串发送


33
投票

这些对我来说都不起作用,直到我通过 JS 在请求标头上设置

X-CSRF-Token
值,如下所示:

request.setRequestHeader('X-CSRF-Token', token)

token
当然是 CSRF 代币。我从
<meta name="csrf-token">
标签得到这个,没有使用
encodeURIComponent()

更新,因为这对某些人来说很有用

总而言之:

var token = document.querySelector('meta[name="csrf-token"]').content
request.setRequestHeader('X-CSRF-Token', token)

15
投票

谢谢!

只是为了更常见的用途而澄清。

您需要在头脑中添加带有 var AUTH_TOKEN 的 js 标签。应该是这样的。

<%= csrf_meta_tag %>
<%= javascript_tag "var AUTH_TOKEN = '#{form_authenticity_token}';" if protect_against_forgery? %>

然后,如果您不需要使用parent(form)或类似的东西,只需将authenticity_token = AUTH_TOKEN放入ajax数据中即可。

$.ajax({
  type: 'post',
  dataType:'text',
  data: "user_id="+user_id+"&authenticity_token="+AUTH_TOKEN,
  url:'/follow/unfollow'
})

感谢上面的朋友分享这些知识!


8
投票

在 Rails 5.1+ 中,如果您使用内置的

Rails
JS 助手来处理 AJAX 请求(来自
rails-ujs
),则会自动附加 CSRF 令牌,例如:

Rails.ajax({
  url: "/your/url",
  type: "POST",
  data: "a=1&b=2",
  success: function(data) {
    console.log(data);
  }
});

如果您需要的话,该库还为您提供手动获取 CSRF 令牌的帮助器:

Rails.csrfToken();

3
投票

您可以将 AUTH_TOKEN 包含在表单本身中,作为隐藏输入。

<input type="hidden" name="AUTH_TOKEN">1234abcd</input>

3
投票

我刚刚遇到了这个问题,但我在我的 application.js 文件中尝试了这种方法:

$(document).ajaxSend(function(e, xhr, options) {
  if (options.data == null) {
    options.data = {};
  }
  options.data['authenticity_token'] = token;
});

这是我得到这个想法的原始问题:ajaxSend Question


2
投票

这是一个适用于所有 AJAX 请求的解决方案。 您将以下内容添加到您的 all.js (或您的站点范围内的任何 javascript 文件)

$.ajaxSetup({
    headers: {
        'X-CSRF-Token': document.querySelector('meta[name="csrftoken"]').content
    }
});

这会自动将令牌添加为所有 AJAX 请求的标头。在 Rails 7 中为我工作。


0
投票

只需使用 form_tag 就会自动包含 CSRF 令牌参数。 Rails 支持“Unobtrusive Javascript”,这意味着表单仍将通过 AJAX 提交。控制器操作支持“respond_to”块,您可以使用 .js.erb 扩展名在网页上进行更改以响应表单提交。


0
投票

使用 Rails 6.1,此处发布的包含 CSRFToken 的解决方案对我不起作用。这是现在有效的方法。

csrfToken = document.querySelector("meta[name='csrftoken']").getAttribute("content"); fetch("your_action_path", {
       method: 'POST',
       headers:  {
       "X-CSRF-Token": csrfToken,
      "Content-Type": "application/json",
      "Accept": "application/json"
      },
      body: JSON.stringify(your data for your post)    });
© www.soinside.com 2019 - 2024. All rights reserved.