jQuery 如何在表单的 AJAX 发布请求中传递 CSRF 令牌?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45470802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 19:25:38  来源:igfitidea点击:

How to pass along CSRF token in an AJAX post request for a form?

jqueryajaxscalaplayframeworkcsrf

提问by NateH06

I'm using Scala Play! 2.6 Framework, but that may not be the issue. I'm using their Javascript routing - and it seems to work ok, but it's having issues. I have a form, which when rendered produces this, with a CSRF token:

我正在使用 Scala Play!2.6 框架,但这可能不是问题。我正在使用他们的 Javascript 路由 - 它似乎工作正常,但它有问题。我有一个表单,它在呈现时会产生这个,带有一个 CSRF 令牌:

<form method="post" id="myForm" action="someURL">

<input name="csrfToken" value="5965f0d244b7d32b334eff840...etc" type="hidden">
  <input type="text" id="sometext">
  <button type="submit"> Submit! </button>

</form>

And here's roughly, my AJAX:

这是我的 AJAX:

$(document).on('submit', '#myForm', function (event) {

 event.preventDefault();
   var data = {
    textvalue: $('#sometext').val()
   }
 var route = jsRoutes.controllers.DashboardController.postNewProject()
 $.ajax({
    url: route.url,
    type: route.type,
    data : JSON.stringify(data),
    contentType : 'application/json',
    success: function (data) { ...      },
    error: function (data) { ...  }
        })

});

But when I post this, I am getting an UNAUTHORIZED response back from my Server, and my console in IntelliJ is telling me the CSRF check is failing. How would I pass along the CSRF token in the request?

但是当我发布这个时,我从我的服务器收到了一个未经授权的响应,我在 IntelliJ 中的控制台告诉我 CSRF 检查失败。我将如何在请求中传递 CSRF 令牌?

回答by NateH06

Ok, after fighting this for a few hours and trying to decrypt Play's frequently-lacking-context-Documentation on the subject, I've got it.

好吧,经过几个小时的斗争并试图解密 Play 经常缺乏的关于这个主题的上下文文档,我明白了。

So, from their docs:

所以,从他们的文档:

To allow simple protection for non browser requests, Play only checks requests with cookies in the header. If you are making requests with AJAX, you can place the CSRF token in the HTML page, and then add it to the request using the Csrf-Tokenheader.

为了对非浏览器请求进行简单保护,Play 仅检查标头中带有 cookie 的请求。如果您使用 AJAX 发出请求,您可以将 CSRF 令牌放在 HTML 页面中,然后使用Csrf-Token标头将其添加到请求中。

And then there's no code or example. Thanks Play. Very descriptive. Anyway, here's how:

然后没有代码或示例。感谢播放。描述性很强。无论如何,方法如下:

in your view.html.formTemplateyou might write in IntelliJ:

在你的view.html.formTemplate,你可能会在的IntelliJ写:

@()
<form method="post" id="myForm" action="someURL">

@helper.CSRF.formField  <!-- This auto-generates a token for you -->
  <input type="text" id="sometext">
  <button type="submit"> Submit! </button>

</form>

And this will render like this when delivered to the client:

这将在交付给客户端时呈现如下:

<form method="post" id="myForm" action="someURL">

<input name="csrfToken" value="5965f0d244b7d32b334eff840...etc" type="hidden">
  <input type="text" id="sometext">
  <button type="submit"> Submit! </button>

</form>

Ok, almost there, now we have to create our AJAX call. I have all of mine in a separate main.js file, but you could also put this in your view.html.formTemplateif you want.

好的,差不多了,现在我们必须创建我们的 AJAX 调用。我所有的都在一个单独的 main.js 文件中,但view.html.formTemplate如果你愿意,你也可以把它放在你的文件中。

$(document).on('submit', '#myForm', function (event) {

 event.preventDefault();
   var data = {
    myTextToPass: $('#sometext').val()
   }
 // LOOK AT ME! BETWEEN HERE AND
 var token =  $('input[name="csrfToken"]').attr('value')
    $.ajaxSetup({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('Csrf-Token', token);
        }
    });
// HERE
 var route = jsRoutes.controllers.DashboardController.postNewProject()
 $.ajax({
    url: route.url,
    type: route.type,
    data : JSON.stringify(data),
    contentType : 'application/json',
    success: function (data) { ...      },
    error: function (data) { ...  }
        })

});

With this line: var token = $('input[name="csrfToken"]').attr('value')You are plucking out the CSRF token auto generated in your form field and grabbing its value in a var to be used in your Javascript.

使用这一行: var token = $('input[name="csrfToken"]').attr('value')您将提取在表单字段中自动生成的 CSRF 令牌,并在要在您的 Javascript 中使用的 var 中获取其值。

The other important chunk from all that AJAX is here:

AJAX 中的另一个重要部分在这里:

$.ajaxSetup({
            beforeSend: function(xhr) {
                xhr.setRequestHeader('Csrf-Token', token);
            }
        });

Using the $.ajaxSetup, you can set what's in the header. This is what you have to infer from their documentation:

使用$.ajaxSetup,您可以设置标题中的内容。这是您必须从他们的文档中推断出的内容:

add it to the request using the Csrf-Token header.

使用 Csrf-Token 标头将其添加到请求中。

Good luck! Let me know if this is clear.

祝你好运!让我知道这是否清楚。



Note: when using lusca, use X-CSRF-Tokeninstead of Csrf-Token.

注意:使用lusca 时,请使用X-CSRF-Token代替Csrf-Token

回答by MOnkey

From JSP

从 JSP

<form method="post" id="myForm" action="someURL">
    <input name="csrfToken" value="5965f0d244b7d32b334eff840...etc" type="hidden">    
</form>

This is the simplest way that worked for me after struggling for 3hrs, just get the token from input hidden field like this and while doing the AJAX request to just need to pass this token in header as follows:-

这是在挣扎了 3 小时后对我有用的最简单的方法,只需像这样从输入隐藏字段中获取令牌,并且在执行 AJAX 请求时只需要在标头中传递此令牌,如下所示:-

From JQuery

来自 JQuery

var token =  $('input[name="csrfToken"]').attr('value'); 

From plain Javascript

来自普通的 Javascript

var token = document.getElementsByName("csrfToken").value;

Final AJAX Request

最终的 AJAX 请求

$.ajax({
      url: route.url,
      data : JSON.stringify(data),
      method : 'POST',
      headers: {
                    'X-CSRF-Token': token 
               },
      success: function (data) { ...      },
      error: function (data) { ...  }

});

});

Now you don't need to disable crsf security in web config, and also this will not give you 405( Method Not Allowed) error on console.

现在你不需要在 web 配置中禁用 crsf 安全性,而且这不会在控制台上给你 405(Method Not Allowed) 错误。

Hope this will help people..!!

希望这会帮助人们.. !!

回答by inieto

add it to the request using the Csrf-Tokenheader.

使用Csrf-Token标头将其添加到请求中。

Thanks NateH06for the header name! I was trying to send csrf token for a "delete" button with an ajax function call and I was stuck on the following:

感谢NateH06提供标题名称!我试图通过 ajax 函数调用为“删除”按钮发送 csrf 令牌,但我遇到了以下问题:

@import helper._
....
<button id="deleteBookBtn" class="btn btn-danger"
        data-csrf-name="@helper.CSRF.getToken.name"
        data-csrf-value="@helper.CSRF.getToken.value"
        data-delete-url="@routes.BooksController.destroy(book.id)"
        data-redirect-url="@routes.HomeController.index()">Delete</button>

I wasn't able to add online js within the onclick()event because of a CSP set on play 2.6 too.

onclick()由于在 play 2.6 上设置了 CSP,我也无法在活动中添加在线 js 。

Refused to execute inline event handler because it violates the following Content Security Policy directive: "default-src 'self'".

拒绝执行内联事件处理程序,因为它违反了以下内容安全策略指令:“default-src 'self'”。

And on the JS file:

在 JS 文件上:

function sendDeleteRequest(event) {
  url = event.target.getAttribute("data-delete-url")
  redirect = event.target.getAttribute("data-redirect-url")
  csrfTokenName = event.target.getAttribute("data-csrf-name")
  csrfTokenValue = event.target.getAttribute("data-csrf-value")
  $.ajax({
    url: url,
    method: "DELETE",
    beforeSend: function(request) {
      //'Csrf-Token' is the expected header name, not $csrfTokenName
      request.setRequestHeader(/*$csrfTokenName*/'Csrf-Token', csrfTokenValue);
    },
    success: function() {
      window.location = redirect;
    },
    error: function() {
      window.location.reload();
    }
  })
}

var deleteBookBtn = document.getElementById("deleteBookBtn");
if(deleteBookBtn) {
    deleteBookBtn.addEventListener("click", sendDeleteRequest);
}

After setting the header name as 'Csrf-Token'the ajax call works perfectly!

将标题名称设置为'Csrf-Token'ajax 调用后完美运行!

回答by fredex42

In case it's of use to anyone else who is googling around trying to understand why they can't get the correct token to appear.... I've been struggling with the same issue for a Play backend/React frontend combination - and hence unable to (easily) use the token-in-htmlpage technique I eventually came across another solution for setting the current token in a cookie... simply add:

万一它对正在谷歌搜索试图理解为什么他们无法获得正确令牌出现的任何其他人有用....无法(轻松)使用 token-in-htmlpage 技术我最终遇到了另一种在 cookie 中设置当前令牌的解决方案......只需添加:

play.filters.csrf {
  cookie.name = "csrftoken"
}

to application.conf and the csrftokencookie will be set to the token. I then used https://www.npmjs.com/package/js-cookieto grab the value in my JS code and send it back in the request header - not including the code here as it's React not jQuery as for the OP and don't want to confuse matters.

到 application.conf 并且csrftokencookie 将被设置为令牌。然后我使用https://www.npmjs.com/package/js-cookie来获取我的 JS 代码中的值并将其发送回请求标头 - 不包括这里的代码,因为它是 React 而不是 jQuery 作为 OP 和不想混淆问题。

回答by Aha00a

You can add Csrf-Tokenheader with headersoption.

您可以Csrf-Token使用headers选项添加标题。

$.ajax({
    url: '@routes.MyController.myPostAction()',
    method: 'post',
    headers: {
        'Csrf-Token': '@play.filters.csrf.CSRF.getToken.map(_.value)'
    },
    data: {
        name: '@name'
    },
    success: function (data, textStatus, jqXHR) {
        location.reload();
    },
    error: function (jqXHR, textStatus, errorThrown) {
        debugger;
    }
});

回答by bmenzel

As stated in the Play Framework 2.6 Documentation, you may set a 'Csrf-Token' Header with the token generated by Play:

正如Play Framework 2.6 文档中所述,您可以Csrf-Token使用 Play 生成的令牌设置一个“ ”标头:

If you are making requests with AJAX, you can place the CSRF token in the HTML page, and then add it to the request using the Csrf-Tokenheader.

如果您使用 AJAX 发出请求,您可以将 CSRF 令牌放在 HTML 页面中,然后使用Csrf-Token标头将其添加到请求中。

Within a Scala-Template you can get the token-value using @helper.CSRF.getToken.value

在 Scala 模板中,您可以使用 @helper.CSRF.getToken.value

Following jQuerys Documentationyou may either set it once for all Ajax requests by configuring jQuery using ajaxSetup

按照jQuery 文档,您可以通过使用ajaxSetup配置 jQuery 为所有 Ajax 请求设置一次

$.ajaxSetup({
  beforeSend: function(xhr) {
    xhr.setRequestHeader('Csrf-Token', '@helper.CSRF.getToken.value');
  }
});

or alternatively set the Header on every Request by configuring the headersobject like this:

或者通过headers像这样配置对象来设置每个请求的标头:

$.ajax({
  url: route.url,
  ...
  headers: {
    'Csrf-Token': '@helper.CSRF.getToken.value'
  }
});