Mancata corrispondenza del token csrf di Laravel per la richiesta POST ajax


113

Sto cercando di eliminare i dati dal database tramite ajax.

HTML:

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

Il mio codice 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;
}
});

Questa è la mia richiesta per recuperare i dati dal database ...

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

Ma quando faccio clic su Elimina i dati del collegamento non eliminati e mostro la mancata corrispondenza di csrf_token ...



dovresti aggiungere successo ed errore al tuo codice ajax. l'errore mostrerà il problema. stackoverflow.com/questions/45668337/...
Reza Jafari

Risposte:


176

Devi aggiungere i dati nella tua richiesta ajax. Spero che funzioni.

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

32
E se la funzione ajax si trova nel .jsfile?
Brane

1
Non funziona su Laravel 5.7. la risposta di zarpio è corretta.
Omar Murcia

1
@Brane invia il token come parametro nella funzione
Abdelalim Hassouna

Questo non funziona in Laravel 5.8. Si dice ancora che il token non corrisponde. Controlla la mia risposta qui sotto per una soluzione semplice
Gjaa

laravel cambia il token csrf dopo una richiesta json? devi inviare quello nuovo alla pagina principale?
davefrassoni

184

Il modo migliore per risolvere questo problema "X-CSRF-TOKEN" è aggiungere il seguente codice al layout principale e continuare a effettuare normalmente le chiamate ajax:

Nell'intestazione

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

Nello script

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

5
Grazie uomo. Questa è una soluzione più completa! In questo modo devi solo configurarlo una volta e successivamente scrivere il tuo normale codice $ .ajax.
pkid169

4
Questa è la soluzione migliore perché puoi usarla all'interno dei .jsfile
Adam

3
La migliore risposta finora. Grazie.
Paul Denisevich

e se "globale: falso"?
Michel

1
Come può essere aggiornato il csrf dopo ogni chiamata? la prima chiamata funziona alla grande, le chiamate secondarie falliscono a causa del token CSRF.
Jjsg08

28

Penso che sia meglio mettere il token nel modulo e ottenere questo token da id

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

E il JQUery:

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

in questo modo, il tuo JS non ha bisogno di essere nei tuoi file blade.


25

Ho appena aggiunto headers:in ajax call:

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

in vista:

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

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

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

nel controller:

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

in route.php

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

1
l'aggiunta di intestazioni alla chiamata ajax mi ha aiutato.
Chaudhry Waqas

1
Questa è la risposta migliore perché non richiede che JavaScript sia in un file blade (a meno che tu non lo voglia in un file blade, ma poi viene renderizzato ogni volta che qualcuno arriva a quella pagina)
Zachary Weixelbaum

11

Se stai usando file modello, puoi mettere il tuo metatag nell'head section(o come lo chiami) che contiene i tuoi metatag.

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

La prossima cosa, devi mettere l' headersattributo al tuo ajax(nel mio esempio, sto usando datatablecon l'elaborazione lato server:

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

Ecco l' datatableesempio completo di Ajax:

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

Dopo averlo fatto, dovresti ricevere la 200 statustua ajaxrichiesta.


6

Sappi che esiste un cookie X-XSRF-TOKEN impostato per comodità. Framework come Angular e altri lo impostano di default. Controlla questo nel documento https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token Potrebbe piacerti usarlo.

Il modo migliore è utilizzare il meta, nel caso in cui i cookie siano disattivati.

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

Ecco il meta way consigliato (puoi inserire il campo in qualsiasi modo, ma il meta è abbastanza carino):

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

Notare l'uso di decodeURIComponent(), è decodificato dal formato uri che viene utilizzato per memorizzare il cookie. [altrimenti otterrai un'eccezione di payload non valida in laravel].

Qui la sezione sul cookie csrf nel documento da controllare: https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

Anche qui come laravel (bootstrap.js) lo sta impostando per axios di default:

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

puoi andare a controllare resources/js/bootstrap.js.

E qui leggi la funzione 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

Aggiungere un idl' metaelemento che contiene il token

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

E poi puoi ottenerlo nel tuo Javascript

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

1
Se non vuoi aggiungere un id, usa semplicemente: $ ("[name = csrf-token]"). Attr ("content") invece. Recupererà l'elemento giusto dall'attributo name.
Pedro Sousa

3

se stai usando jQuery per inviare post AJAX, aggiungi questo codice a tutte le visualizzazioni:

$( 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 aggiunge un cookie XSRF a tutte le richieste e lo accodiamo automaticamente a tutte le richieste AJAX appena prima dell'invio.

Puoi sostituire la funzione getCookie se c'è un'altra funzione o plugin jQuery per fare la stessa cosa.


1

Per Laravel 5.8, l'impostazione del metatag csrf per il layout e l'impostazione dell'intestazione della richiesta per csrf nelle impostazioni ajax non funzioneranno se si utilizza ajax per inviare un modulo che include già un _tokencampo di input generato dal motore di modelli di Laravel blade.

Devi includere il token csrf già generato dal modulo con la tua richiesta ajax perché il server lo aspetterebbe e non quello nel tuo meta tag.

Ad esempio, questo è l' _tokenaspetto del campo di input generato da Blade:

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

Quindi invia il tuo modulo con ajax in questo modo:

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

Il token csrf nel meta header è utile solo quando si invia un modulo senza un _tokencampo di input generato da Blade .


1

chi ha problemi con la risposta accettata @Deepak saini, prova a rimuovere

cache:false,
processData:false,
contentType:false,

per ajax call.

uso

dataType:"json",

0

Ho effettivamente avuto questo errore e non sono riuscito a trovare una soluzione. In realtà ho finito per non fare una richiesta ajax. Non so se questo problema fosse dovuto al fatto che si trattava di un sottodominio sul mio server o cosa. Ecco il mio 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" );
                        }
                      }
                    });
                  });
                });

Quindi ho effettivamente impostato un'ancora per andare alla mia API piuttosto che fare una richiesta di post, che è ciò che immagino faccia la maggior parte delle applicazioni.

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

0

È necessario includere un campo token CSRF (cross site request forgery) nascosto nel modulo in modo che il middleware di protezione CSRF possa convalidare la richiesta.

Laravel genera automaticamente un "token" CSRF per ogni sessione utente attiva gestita dall'applicazione. Questo token viene utilizzato per verificare che l'utente autenticato sia quello che effettivamente effettua le richieste all'applicazione.

Quindi, quando esegui richieste ajax, dovrai passare il token csrf tramite il parametro data. Ecco il codice di esempio.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.