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

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

我正在使用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) { ...  }
        })

});

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

jquery ajax scala playframework csrf
5个回答
18
投票

好吧,经过几个小时的斗争,并试图解密在subject上播放频繁缺乏上下文的文档,我已经明白了。

所以,从他们的文档:

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

然后没有代码或示例。谢谢玩。非常具有描述性。无论如何,这是如何:

在你的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,您可以设置标题中的内容。这是你必须从他们的文档推断:

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

祝好运!如果这一点很清楚,请告诉我。


注意:使用lusca时,请使用X-CSRF-Token而不是Csrf-Token


2
投票

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

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

我无法在onclick()事件中添加在线js,因为CSP也设置在2.6。

拒绝执行内联事件处理程序,因为它违反了以下内容安全策略指令:“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);
}

将标题名称设置为'Csrf-Token'后,ajax调用完美无缺!


1
投票

来自JSP

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

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

来自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-CSRF-Token': token 
               },
      success: function (data) { ...      },
      error: function (data) { ...  }

});

现在您不需要在Web配置中禁用csrf安全性,并且这也不会在控制台上提供405(Method Not Allowed)错误。

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


0
投票

您可以使用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;
    }
});

0
投票

Play Framework 2.6 Documentation中所述,您可以使用Play生成的令牌设置'Csrf-Token'标头:

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

在Scala-Template中,您可以使用@helper.CSRF.getToken.value获取令牌值

jQuerys Documentation之后,您可以通过使用ajaxSetup配置jQuery来为所有Ajax请求设置一次

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

或者通过配置headers对象在每个请求上设置Header,如下所示:

$.ajax({
  url: route.url,
  ...
  headers: {
    'Csrf-Token': '@helper.CSRF.getToken.value'
  }
});
© www.soinside.com 2019 - 2024. All rights reserved.