Laravel CSRF令牌与Ajax POST请求不匹配


112

我正在尝试通过ajax从数据库中删除数据。

HTML:

@foreach($a as $lis)
  //some code
  <a href="#" class="delteadd" id="{{$lis['id']}}">Delete</a>
  //click action perform on this link                  
@endforeach

我的ajax代码:

$('body').on('click', '.delteadd', function (e) {
e.preventDefault();
//alert('am i here');
if (confirm('Are you sure you want to Delete Ad ?')) {
    var id = $(this).attr('id');
    $.ajax({
        method: "POST",
        url: "{{url()}}/delteadd",
        }).done(function( msg ) {
        if(msg.error == 0){
            //$('.sucess-status-update').html(msg.message);
            alert(msg.message);
        }else{
            alert(msg.message);
            //$('.error-favourite-message').html(msg.message);
        }
    });
} else {
    return false;
}
});

这是我从数据库中获取数据的查询...

$a = Test::with('hitsCount')->where('userid', $id)->get()->toArray();

但是,当我单击删除链接数据未删除并显示csrf_token不匹配时...



您应该在ajax代码中添加成功和错误。错误将显示问题。stackoverflow.com/questions/45668337/...
礼萨·贾法里

Answers:


175

您必须在ajax请求中添加数据。我希望这样会有用。

data: {
        "_token": "{{ csrf_token() }}",
        "id": id
        }

32
如果ajax函数位于.js文件中怎么办?
Brane

1
它在Laravel 5.7上不起作用。zarpio的答案是正确的。
奥马尔·穆尔西亚

1
@Brane将令牌作为函数中的参数发送
Abdelalim Hassouna

这在Laravel 5.8中不起作用。它仍然说令牌不匹配。在下面查看我的答案以找到一种简单的解决方案
Gjaa

laravel在json请求后更改csrf令牌吗?您需要将新的发送到主页吗?
davefrassoni

184

解决此问题“ X-CSRF-TOKEN”的最佳方法是在主布局中添加以下代码,然后继续正常进行ajax调用:

在标题中

<meta name="csrf-token" content="{{ csrf_token() }}" />

在脚本中

<script type="text/javascript">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
</script>

5
谢啦。这是一个更完善的解决方案!这样,您只需设置一次,然后再编写常规的$ .ajax代码即可。
pkid169

4
这是更好的解决方案,因为您可以在.js文件中使用它
Adam

3
到目前为止最好的答案。谢谢。
Paul Denisevich

如果“ global:false”怎么办?
米歇尔

每次调用后如何更新csrf?第一次通话效果很好,由于CSRF令牌,次安全通话失败。
Jjsg08

28

我认为最好将令牌放入表单中,并通过id获取此令牌

<input type="hidden" name="_token" id="token" value="{{ csrf_token() }}">

还有JQUery:

var data = {
        "_token": $('#token').val()
    };

这样,您的JS不必放在刀片文件中。


25

我刚刚添加headers:了ajax调用:

  headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},

鉴于:

<div id = 'msg'>
     This message will be replaced using Ajax. Click the button to replace the message.
</div>

{{ Form::submit('Change', array('id' => 'ajax')) }}

Ajax函数:

<script>
 $(document).ready(function() {
    $(document).on('click', '#ajax', function () {
      $.ajax({
         type:'POST',
         url:'/ajax',
         headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
         success:function(data){
            $("#msg").html(data.msg);
         }
      });
    });
});
</script>

在控制器中:

public function call(){
    $msg = "This is a simple message.";
    return response()->json(array('msg'=> $msg), 200);
}

在routes.php中

Route::post('ajax', 'AjaxController@call');

1
在ajax调用中添加标题有助于我。
Chaudhry Waqas

1
这是最好的答案,因为它不需要JavaScript放在刀片文件中(除非您希望将其放在刀片文件中,但是每次有人访问该页面时都会呈现它)
Zachary Weixelbaum

11

如果您正在使用模板文件,则可以将meta标签放在包含标签的头部section(或任何您喜欢的名称)中meta

@section('head')
<meta name="csrf_token" content="{{ csrf_token() }}" />
@endsection

接下来,您需要将headers属性放入您的ajax示例中(在我的示例中,我正在使用datatable服务器端处理:

"headers": {'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content')}

这是完整的datatableajax示例:

$('#datatable_users').DataTable({
        "responsive": true,
        "serverSide": true,
        "processing": true,
        "paging": true,
        "searching": { "regex": true },
        "lengthMenu": [ [10, 25, 50, 100, -1], [10, 25, 50, 100, "All"] ],
        "pageLength": 10,
        "ajax": {
            "type": "POST",
            "headers": {'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content')},
            "url": "/getUsers",
            "dataType": "json",
            "contentType": 'application/json; charset=utf-8',
            "data": function (data) {
                console.log(data);
            },
            "complete": function(response) {
                console.log(response);
           }
        }
    });

完成此操作后,您应该得到200 status您的ajax请求。


6

为了方便起见,知道有一个X-XSRF-TOKEN cookie。默认情况下,Angular等框架和其他框架会对其进行设置。在文档https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token中进行检查。 您可能想使用它。

最好的方法是使用元数据,以防止禁用cookie。

    var xsrfToken = decodeURIComponent(readCookie('XSRF-TOKEN'));
    if (xsrfToken) {
        $.ajaxSetup({
            headers: {
                'X-XSRF-TOKEN': xsrfToken
            }
        });
    } else console.error('....');

这里是推荐的meta方法(您可以以任何方式放置字段,但是meta很安静):

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});   

注意使用decodeURIComponent(),它是从uri格式解码的,用于存储cookie。[否则,您将在laravel中获得无效的有效负载异常]。

这里是有关文档中要检查的csrf cookie的部分:https ://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

同样在这里laravel(bootstrap.js)如何默认为axios设置它:

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
} 

你可以去检查一下resources/js/bootstrap.js

在这里读取cookie函数:

   function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
       }
        return null;
    }

5

idmeta包含令牌的元素添加一个

<meta name="csrf-token" id="csrf-token" content="{{ csrf_token() }}">

然后可以在Javascript中获取它

$.ajax({
  url : "your_url",
  method:"post",
  data : {
    "_token": $('#csrf-token')[0].content  //pass the CSRF_TOKEN()
  },  
  ...
});

1
如果您不想添加ID,只需使用:$(“ [[name = csrf-token]”)。attr(“ content”)。它将通过name属性获取正确的元素。
Pedro Sousa

3

如果您使用jQuery发送AJAX帖子,请将此代码添加到所有视图:

$( document ).on( 'ajaxSend', addLaravelCSRF );

function addLaravelCSRF( event, jqxhr, settings ) {
    jqxhr.setRequestHeader( 'X-XSRF-TOKEN', getCookie( 'XSRF-TOKEN' ) );
}

function getCookie(name) {
    function escape(s) { return s.replace(/([.*+?\^${}()|\[\]\/\\])/g, '\\$1'); };
    var match = document.cookie.match(RegExp('(?:^|;\\s*)' + escape(name) + '=([^;]*)'));
    return match ? match[1] : null;
}

Laravel将XSRF cookie添加到所有请求,并且在提交之前,我们会自动将其附加到所有AJAX请求中。

如果有另一个函数或jQuery插件可以执行相同的操作,则可以替换getCookie函数。


1

对于Laravel 5.8,如果使用ajax提交已经包含_tokenLaravel刀片模板引擎生成的输入字段的表单,则在布局中设置csrf元标记和在ajax设置中设置csrf的请求标头将不起作用。

您必须在表单中包含已经从表单生成的csrf令牌以及ajax请求,因为服务器将期望它,而不是您的meta标记中的那个。

例如,这就是_tokenBlade生成的输入字段的样子:

<form>
    <input name="_token" type="hidden" value="cf54ty6y7yuuyyygytfggfd56667DfrSH8i">
    <input name="my_data" type="text" value="">
    <!-- other input fields -->
</form>

然后,使用ajax提交表单,如下所示:

<script> 
    $(document).ready(function() { 
        let token = $('form').find('input[name="_token"]').val();
        let myData = $('form').find('input[name="my_data"]').val();
        $('form').submit(function() { 
            $.ajax({ 
                type:'POST', 
                url:'/ajax', 
                data: {_token: token, my_data: myData}
                // headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')}, // unnecessary 
                // other ajax settings
            }); 
            return false;
        }); 
    }); 
</script>

仅当您提交不带Blade生成的_token输入字段的表单时,meta标题中的csrf令牌才有用。



0

我实际上有此错误,找不到解决方案。我实际上最终没有执行ajax请求。我不知道此问题是否是由于服务器上的子域或什么原因引起的。这是我的jQuery。

            $('#deleteMeal').click(function(event) {
                var theId = $(event.currentTarget).attr("data-mealId");
                  $(function() {
                    $( "#filler" ).dialog({
                      resizable: false,
                      height:140,
                      modal: true,
                      buttons: {
                      "Are you sure you want to delete this Meal? Doing so will also delete this meal from other users Saved Meals.": function() {
                           $('#deleteMealLink').click();
//                         jQuery.ajax({
//                              url : 'http://www.mealog.com/mealtrist/meals/delete/' + theId,
//                              type : 'POST',
//                              success : function( response ) {
//                                  $("#container").replaceWith("<h1 style='color:red'>Your Meal Has Been Deleted</h1>");
//                              }
//                          });
                        // similar behavior as clicking on a link
                           window.location.href = 'http://www.mealog.com/mealtrist/meals/delete/' + theId;
                          $( this ).dialog( "close" );
                        },
                        Cancel: function() {
                          $( this ).dialog( "close" );
                        }
                      }
                    });
                  });
                });

因此,我实际上设置了一个锚点以转到我的API,而不是执行发布请求,这是我认为大多数应用程序所做的事情。

  <p><a href="http://<?php echo $domain; ?>/mealtrist/meals/delete/{{ $meal->id }}" id="deleteMealLink" data-mealId="{{$meal->id}}" ></a></p>

0

您应该在表单中包含一个隐藏的CSRF(跨站点请求伪造)令牌字段,以便CSRF保护中间件可以验证请求。

Laravel为由应用程序管理的每个活动用户会话自动生成CSRF“令牌”。此令牌用于验证经过身份验证的用户实际上是对应用程序的请求。

因此,在执行ajax请求时,您需要通过data参数传递csrf令牌。这是示例代码。

var request = $.ajax({
    url : "http://localhost/some/action",
    method:"post",
    data : {"_token":"{{ csrf_token() }}"}  //pass the CSRF_TOKEN()
  });

0

我只是在表单中使用@csrf,并且工作正常

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.