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

时间:2017-08-02 20:53:05

标签: jquery ajax scala playframework csrf

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

6 个答案:

答案 0 :(得分:18)

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

所以,从他们的文档:

  

为了允许对非浏览器请求进行简单保护,请仅播放检查   标题中包含cookie的请求。如果您正在提出请求   AJAX,您可以将CSRF令牌放在HTML页面中,然后添加它   使用Csrf-Token标题的请求。

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

你可能用IntelliJ写的view.html.formTemplate中的

@()
<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

答案 1 :(得分:2)

  

使用@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> 标题将其添加到请求中。

感谢 NateH06 作为标题名称!我试图为&#34;删除&#34;发送csrf令牌。带有ajax函数调用的按钮,我被困在以下内容:

onclick()

我无法在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); } 事件中添加在线js,因为CSP也设置为2.6。

  

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

在JS文件上:

'Csrf-Token'

将标题名称设置为<?php ... old code while($row=mysql_fetch_array($result)){?> <img src="../<?php echo $row['username'];?>/upload/"<?php echo $row['name'];?>"> } ?> 后,ajax调用完美无缺!

答案 2 :(得分: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;
    }
});

答案 3 :(得分:0)

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

  

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

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

获取令牌值

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

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

或通过如下配置headers对象在每个请求上设置标头:

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

答案 4 :(得分:0)

以防其他人在试图了解为什么他们无法获得正确的令牌出现的情况下使用它。...我一直在为Play后端/ React前端组合解决相同的问题-因此无法(轻松地)使用html页面中的令牌技术,我最终遇到了另一种在cookie中设置当前令牌的解决方案...只需添加:

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

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

答案 5 :(得分:0)

slim csrf gurd ,通过wig在slim应用程序中在jQuery中传递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}}";
        }
    });
});