Proper way to send an Authenticity Token with AJAX

2019-01-16 18:37发布

This works but gets stopped because it lacks an authenticity token:

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

So I tried adding it like so:

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

And it passes the auth_token correctly as a param, but seems to lose the rest of my form.

Anyways to accomplish both sending the form data that works, and the authenticity token as well?

This is a rails environment. And I have this in my head.

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

Things I've tried

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 );
    }
});

7条回答
放荡不羁爱自由
2楼-- · 2019-01-16 18:38

I just ran into this issue but I tried this approach in my application.js file:

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

This is the original question where I got the idea: ajaxSend Question

查看更多
可以哭但决不认输i
3楼-- · 2019-01-16 18:39

This token also already appears in one of the "meta" tags in the head of the application.html.erb layout file by default if you have the following ERB at the top:

<%= csrf_meta_tag %>

That ERB roughly renders to:

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

You can then grab it using jQuery with the following code:

var AUTH_TOKEN = $('meta[name=csrf-token]').attr('content');
查看更多
趁早两清
4楼-- · 2019-01-16 18:40

Simply using form_tag automatically includes CSRF token parameter. Rails supports "Unobtrusive Javascript" meaning that the form will still be submitted via AJAX. Controller actions support "respond_to" block, and you can use .js.erb extension to make changes on the web page in response to form submit.

查看更多
乱世女痞
5楼-- · 2019-01-16 18:47

Actually, you are reading the action attribute of form and sending a post ajax request to it. to send form data you have to submit the form or you can serialize the form data and send it in ajax request like

$(".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;
});

Doing this will serialize your form data and send it along with ajax request and authenticity token is already being sent via query string

查看更多
放我归山
6楼-- · 2019-01-16 18:51

None of these worked for me until I set the X-CSRF-Token value on the request header via JS like this:

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

token of course, being the CSRF token. I got this from the <meta name="csrf-token"> tag and did not use encodeURIComponent()

Update since this is proving useful to some

So all in all:

var token = document.querySelector('meta[name="csrf-token"]').content
request.setRequestHeader('X-CSRF-Token', token)
查看更多
The star\"
7楼-- · 2019-01-16 18:56

Thanks!

Just to clarify for the more common use.

You need the js tag with var AUTH_TOKEN in your head. Should be something like this.

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

And then simply put your authenticity_token=AUTH_TOKEN in the ajax data if you don't need to use parent(form) or something like this.

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

Thanks to the guys above for sharing this knowledge!

查看更多
登录 后发表回答