Laravel csrf token mismatch for ajax POST Request

2020-01-23 03:05发布

I am trying to delete data from database via ajax.

HTML:

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

My ajax code:

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

This is my query to fetch data from database...

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

But when i click on Delete link data not deleted and show csrf_token mismatch...

11条回答
再贱就再见
2楼-- · 2020-01-23 03:41

Add an id to the meta element that holds the token

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

And then you can get it in your Javascript

$.ajax({
  url : "your_url",
  method:"post",
  data : {
    "_token": $('#csrf-token')[0].content  //pass the CSRF_TOKEN()
  },  
  ...
});
查看更多
虎瘦雄心在
3楼-- · 2020-01-23 03:41

For Laravel 5.8, setting the csrf meta tag for your layout and setting the request header for csrf in ajax settings won't work if you are using ajax to submit a form that already includes a _token input field generated by the Laravel blade templating engine.

You must include the already generated csrf token from the form with your ajax request because the server would be expecting it and not the one in your meta tag.

For instance, this is how the _token input field generated by Blade looks like:

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

You then submit your form with ajax like this:

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

The csrf token in the meta header is only useful when you are submitting a form without a Blade generated _token input field.

查看更多
劫难
4楼-- · 2020-01-23 03:45

if you are using jQuery to send AJAX Posts, add this code to all views:

$( 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 adds a XSRF cookie to all requests, and we automatically append it to all AJAX requests just before submit.

You may replace getCookie function if there is another function or jQuery plugin to do the same thing.

查看更多
5楼-- · 2020-01-23 03:47

If you are using template files, than you can put your meta tag in the head section (or whatever you name it) which contain your meta tags.

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

Next thing, you need to put the headers attribute to your ajax(in my example, I am using datatable with server-side processing:

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

Here is the full datatable ajax example:

$('#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);
           }
        }
    });

After doing this, you should get 200 status for your ajax request.

查看更多
疯言疯语
6楼-- · 2020-01-23 03:48

I just added headers: in ajax call:

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

in view:

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

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

in controller:

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

in routes.php

Route::post('ajax', 'AjaxController@call');
查看更多
登录 后发表回答