Incompatibilité de jeton Laravel CSRF pour la requête POST Ajax

114

J'essaye de supprimer les données de la base de données 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

Mon code 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;
}
});

Ceci est ma requête pour récupérer les données de la base de données ...

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

Mais lorsque je clique sur Supprimer les données du lien non supprimées et que je montre une discordance csrf_token ...

Ashish Singh
la source
vous devez ajouter le succès et l'erreur à votre code ajax. l'erreur montrera le problème. stackoverflow.com/questions/45668337/…
reza jafari

Réponses:

176

Vous devez ajouter des données dans votre requête ajax. J'espère que ce sera du travail.

data: {
        "_token": "{{ csrf_token() }}",
        "id": id
        }
Deepak saini
la source
32
Que faire si la fonction ajax se trouve dans le .jsfichier?
Brane
1
Cela ne fonctionne pas sur Laravel 5.7. La réponse de zarpio est correcte.
Omar Murcia
1
@Brane envoie le jeton en tant que paramètre dans la fonction
Abdelalim Hassouna
Cela ne fonctionne pas dans Laravel 5.8. Il indique toujours une discordance de jetons. Vérifiez ma réponse ci-dessous pour une solution simple
Gjaa
laravel change-t-il le jeton csrf après une requête json? avez-vous besoin d'envoyer le nouveau à la page principale?
davefrassoni
185

La meilleure façon de résoudre ce problème "X-CSRF-TOKEN" est d'ajouter le code suivant à votre mise en page principale et de continuer à faire vos appels ajax normalement:

Dans l'en-tête

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

Dans le script

<script type="text/javascript">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
</script>
Zarpio
la source
5
Merci mec. C'est une solution plus complète! De cette façon, vous ne le configurez qu'une fois et par la suite, écrivez votre code $ .ajax normal.
pkid169 du
4
C'est la meilleure solution car vous pouvez l'utiliser dans des .jsfichiers
Adam
3
Meilleure réponse à ce jour. Merci.
Paul Denisevich
et si "global: faux"?
Michel
1
Comment le CSRF peut-il être mis à jour après chaque appel? le premier appel fonctionne très bien, les appels sous-courants échouent en raison du jeton CSRF.
Jjsg08
28

Je pense qu'il vaut mieux mettre le jeton dans le formulaire et obtenir ce jeton par id

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

Et le JQUery:

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

de cette façon, votre JS n'a pas besoin d'être dans vos fichiers de lame.

cmnardi
la source
25

Je viens d'ajouter headers:dans l'appel ajax:

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

en vue:

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

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

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

dans le contrôleur:

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

dans routes.php

Route::post('ajax', 'AjaxController@call');
lewis4u
la source
1
l'ajout d'en-têtes à l'appel ajax m'a aidé.
Chaudhry Waqas
1
C'est la meilleure réponse car il ne nécessite pas que JavaScript soit dans un fichier lame (à moins que vous ne le souhaitiez dans un fichier lame, mais il est ensuite rendu chaque fois que quelqu'un vient sur cette page)
Zachary Weixelbaum
11

Si vous utilisez des fichiers modèles, vous pouvez mettre votre metabalise dans la tête section(ou quel que soit votre nom) qui contient vos metabalises.

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

Ensuite, vous devez mettre l' headersattribut à votre ajax(dans mon exemple, j'utilise datatableavec le traitement côté serveur:

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

Voici l' datatableexemple complet d' 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);
           }
        }
    });

Après avoir fait cela, vous devriez obtenir 200 statusvotre ajaxdemande.

Brane
la source
6

Sachez qu'il existe un cookie X-XSRF-TOKEN qui est défini pour plus de commodité. Des frameworks comme Angular et d'autres le définissent par défaut. Vérifiez cela dans le doc https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token Vous aimerez peut-être l'utiliser.

Le meilleur moyen est d'utiliser la méta, au cas où les cookies seraient désactivés.

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

Voici la méthode méta recommandée (vous pouvez mettre le champ de toute façon, mais la méta est plutôt sympa):

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

Notez l'utilisation de decodeURIComponent() , il est décodé à partir du format uri qui est utilisé pour stocker le cookie. [sinon vous obtiendrez une exception de charge utile invalide dans laravel].

Voici la section sur le cookie csrf dans la doc à vérifier: https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

Voici également comment laravel (bootstrap.js) le définit par défaut pour 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');
} 

vous pouvez aller vérifier resources/js/bootstrap.js.

Et ici, lisez la fonction de 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;
    }
Mohamed Allal
la source
5

Ajouter un idà l' metaélément contenant le jeton

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

Et puis vous pouvez l'obtenir dans votre Javascript

$.ajax({
  url : "your_url",
  method:"post",
  data : {
    "_token": $('#csrf-token')[0].content  //pass the CSRF_TOKEN()
  },  
  ...
});
Gjaa
la source
1
Si vous ne voulez pas ajouter d'identifiant, utilisez simplement: $ ("[name = csrf-token]"). Attr ("content") à la place. Il récupérera le bon élément par l'attribut name.
Pedro Sousa
3

si vous utilisez jQuery pour envoyer des publications AJAX, ajoutez ce code à toutes les vues:

$( 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 ajoute un cookie XSRF à toutes les demandes, et nous l'ajoutons automatiquement à toutes les demandes AJAX juste avant de les soumettre.

Vous pouvez remplacer la fonction getCookie s'il existe une autre fonction ou un autre plugin jQuery pour faire la même chose.

AMIB
la source
1

Pour Laravel 5.8, définir la balise meta csrf pour votre mise en page et définir l'en-tête de demande pour csrf dans les paramètres ajax ne fonctionnera pas si vous utilisez ajax pour soumettre un formulaire qui comprend déjà un _token champ d'entrée généré par le moteur de création de modèles de lames Laravel.

Vous devez inclure le jeton csrf déjà généré à partir du formulaire avec votre requête ajax car le serveur l'attend et non celui de votre balise meta.

Par exemple, voici à quoi _tokenressemble le champ de saisie généré par Blade:

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

Vous soumettez ensuite votre formulaire avec ajax comme ceci:

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

Le jeton csrf dans l'en-tête méta n'est utile que lorsque vous soumettez un formulaire sans _tokenchamp de saisie généré par Blade .

Udo E.
la source
1

qui a un problème avec la réponse acceptée @Deepak saini, essayez de supprimer

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

pour un appel ajax.

utilisation

dataType:"json",
Mrudul Addipalli
la source
0

J'ai effectivement eu cette erreur et je n'ai pas pu trouver de solution. En fait, j'ai fini par ne pas faire de requête ajax. Je ne sais pas si ce problème était dû au fait qu'il s'agissait d'un sous-domaine sur mon serveur ou quoi. Voici ma question.

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

J'ai donc mis en place une ancre pour accéder à mon API plutôt que de faire une demande de publication, ce que je pense que la plupart des applications font.

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

Vous devez inclure un champ de jeton caché CSRF (contrefaçon de requête intersite) dans le formulaire afin que le middleware de protection CSRF puisse valider la demande.

Laravel génère automatiquement un "token" CSRF pour chaque session utilisateur active gérée par l'application. Ce jeton est utilisé pour vérifier que l'utilisateur authentifié est celui qui fait réellement les requêtes à l'application.

Ainsi, lorsque vous effectuez des requêtes ajax, vous devrez transmettre le jeton csrf via le paramètre data. Voici l'exemple de code.

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

J'utilise juste @csrf dans le formulaire et cela fonctionne bien

moi même
la source