如何在 AJAX post 表单请求中传递 CSRF 令牌?

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

我正在使用 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>

这是我的大致 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) { ...  }
        })

});

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

好吧,经过几个小时的斗争并尝试在 subject 上解密 Play 的 frequently-lacking-context-Documentation,我明白了。

因此,根据他们的文档:

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-Token header.

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

在您的 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>

交付给客户时会呈现这样的效果:

<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>

好的,差不多了,现在我们必须创建我们的 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) { ...  }
        })

});

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

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

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

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

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

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


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

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

感谢 NateH06 header 的名字!我试图通过 ajax 函数调用为 "delete" 按钮发送 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>

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

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

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

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

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

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

来自JSP

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

这是我奋斗了 3 小时后对我有用的最简单的方法,只需像这样从输入隐藏字段中获取令牌,并在执行 AJAX 请求时只需要在 [=30 中传递此令牌=]如下:-

来自JQuery

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

来自普通 Javascript

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

最终AJAX请求

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

现在您不需要在 Web 配置中禁用 crsf 安全性,而且这不会在控制台上给您 405(方法不允许)错误。

希望这会对人们有所帮助..!!

Play Framework 2.6 Documentation 中所述,您可以使用 Play 生成的令牌设置“Csrf-Token”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-Token header.

在 Scala-Template 中,您可以使用 @helper.CSRF.getToken.value

获得 token-value

正在关注 jQuerys Documentation you may either set it once for all Ajax requests by configuring jQuery using ajaxSetup

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

或者通过像这样配置 headers object 在每个请求上设置 Header:

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

万一它对谷歌搜索试图理解为什么他们无法让正确的令牌出现的其他人有用....我一直在为 Play 遇到同样的问题backend/React 前端组合 - 因此无法(轻松)使用 token-in-htmlpage 技术我最终遇到了另一种在 cookie 中设置当前令牌的解决方案...只需添加:

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

到 application.conf 并且 csrftoken cookie 将被设置为令牌。然后我使用 https://www.npmjs.com/package/js-cookie 获取我的 JS 代码中的值并将其发回请求 header - 不包括此处的代码,因为它是 React 而不是 jQuery 至于 OP 并且不要'不想混淆事情。

slim csrf gurd,在jQuery中通过twig

的slim应用程序传递csrf密钥和令牌的方式
$(document).ready(function(){
    $.ajaxPrefilter(function(options, originalOptions, jqXHR){

        var allowedMethod = ["post", "put", "delete"];

        if (allowedMethod.includes(options.type.toLowerCase())  ) {
            // initialize `data` to empty string if it does not exist
            options.data = options.data || "";

            // add leading ampersand if `data` is non-empty
            options.data += options.data?"&":"";

            // add _token entry
            options.data += "{{csrf.keys.name}}={{csrf.name}}&{{csrf.keys.value}}={{csrf.value}}";
        }
    });
});