Laravel csrf no coincide con el token para la solicitud POST de ajax

113

Estoy tratando de eliminar datos de la base de datos a través de ajax.

HTML:

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

Mi código 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;
}
});

Esta es mi consulta para obtener datos de la base de datos ...

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

Pero cuando hago clic en Eliminar datos del enlace no eliminados y muestro csrf_token no coincide ...

Ashish Singh
fuente
debe agregar éxito y error a su código ajax. el error mostrará el problema. stackoverflow.com/questions/45668337/…
reza jafari

Respuestas:

176

Tienes que agregar datos en tu solicitud ajax. Espero que funcione.

data: {
        "_token": "{{ csrf_token() }}",
        "id": id
        }
Deepak Saini
fuente
32
¿Qué pasa si la función ajax se encuentra en el .jsarchivo?
Brane
1
No funciona en Laravel 5.7. La respuesta de zarpio es correcta.
Omar Murcia
1
@Brane envía el token como parámetro en la función
Abdelalim Hassouna
Esto no funciona en Laravel 5.8. Todavía dice falta de coincidencia de tokens. Verifique mi respuesta a continuación para obtener una solución simple
Gjaa
¿Laravel cambia el token csrf después de una solicitud json? ¿Necesitas enviar el nuevo a la página principal?
davefrassoni
184

La mejor manera de resolver este problema "X-CSRF-TOKEN" es agregar el siguiente código a su diseño principal y continuar haciendo sus llamadas ajax normalmente:

En el encabezado

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

En guion

<script type="text/javascript">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
</script>
zarpio
fuente
5
Gracias hombre. ¡Esta es una solución más completa! De esta manera, lo configura una vez y, a partir de entonces, escribe su código $ .ajax normal.
pkid169
4
Esta es la mejor solución porque puede usarla dentro de .jsarchivos
Adam
3
La mejor respuesta hasta ahora. Gracias.
Paul Denisevich
¿y si "global: falso"?
Michel
1
¿Cómo se puede actualizar el csrf después de cada llamada? la primera llamada funciona muy bien, las llamadas posteriores fallan debido al token CSRF.
Jjsg08
28

Creo que es mejor poner el token en el formulario y obtener este token por id

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

Y el JQUery:

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

de esta manera, su JS no necesita estar en sus archivos blade.

cmnardi
fuente
25

Acabo de agregar headers:en una llamada ajax:

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

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

función 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>

en controlador:

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

en rutas.php

Route::post('ajax', 'AjaxController@call');
lewis4u
fuente
1
agregar encabezados a la llamada ajax me ayudó.
Chaudhry Waqas
1
Esta es la mejor respuesta porque no requiere que JavaScript esté en un archivo blade (a menos que lo desee en un archivo blade, pero luego se representa cada vez que alguien llega a esa página)
Zachary Weixelbaum
11

Si está utilizando archivos de plantilla, puede poner su metaetiqueta en el encabezado section(o como lo llame) que contiene sus metaetiquetas.

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

A continuación, debe poner el headersatributo en su ajax(en mi ejemplo, estoy usando datatablecon procesamiento del lado del servidor:

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

Aquí está el datatableejemplo completo de 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);
           }
        }
    });

Después de hacer esto, debería obtener 200 statussu ajaxsolicitud.

Brane
fuente
6

Sepa que hay una cookie X-XSRF-TOKEN que está configurada para su conveniencia. Framework como Angular y otros lo configuran de forma predeterminada. Verifique esto en el documento https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token Es posible que desee usarlo.

La mejor forma es utilizar el meta, en caso de que las cookies estén desactivadas.

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

Aquí la meta forma recomendada (puede poner el campo de cualquier manera, pero la meta es bastante agradable):

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

Tenga en cuenta el uso de decodeURIComponent()su decodificación del formato uri que se utiliza para almacenar la cookie. [de lo contrario, obtendrás una excepción de carga útil no válida en laravel].

Aquí la sección sobre la cookie csrf en el documento para verificar: https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

También aquí cómo laravel (bootstrap.js) lo configura para axios de forma predeterminada:

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

puedes ir a comprobar resources/js/bootstrap.js.

Y aquí lea la función de cookies:

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

Agregue un idal metaelemento que contiene el token

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

Y luego puede obtenerlo en su Javascript

$.ajax({
  url : "your_url",
  method:"post",
  data : {
    "_token": $('#csrf-token')[0].content  //pass the CSRF_TOKEN()
  },  
  ...
});
Gjaa
fuente
1
Si no desea agregar una identificación, simplemente use: $ ("[nombre = csrf-token]"). Attr ("contenido") en su lugar. Buscará el elemento correcto por el atributo de nombre.
Pedro Sousa
3

si está utilizando jQuery para enviar publicaciones AJAX, agregue este código a todas las vistas:

$( 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 agrega una cookie XSRF a todas las solicitudes, y la agregamos automáticamente a todas las solicitudes AJAX justo antes de enviarla.

Puede reemplazar la función getCookie si hay otra función o complemento de jQuery para hacer lo mismo.

AMIB
fuente
1

Para Laravel 5.8, configurar la metaetiqueta csrf para su diseño y configurar el encabezado de solicitud para csrf en la configuración de ajax no funcionará si está utilizando ajax para enviar un formulario que ya incluye un _tokencampo de entrada generado por el motor de plantillas de hoja de Laravel.

Debe incluir el token csrf ya generado del formulario con su solicitud ajax porque el servidor lo estaría esperando y no el de su metaetiqueta.

Por ejemplo, así es como se ve el _tokencampo de entrada generado por Blade:

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

Luego envía su formulario con ajax así:

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

El token csrf en el meta encabezado solo es útil cuando envía un formulario sin un _tokencampo de entrada generado por Blade .

Udo E.
fuente
1

quien tenga problemas con la respuesta aceptada @Deepak saini, intente eliminar

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

para la llamada ajax.

utilizar

dataType:"json",
Mrudul Addipalli
fuente
0

De hecho, tuve este error y no pude encontrar una solución. De hecho, terminé sin hacer una solicitud ajax. No sé si este problema se debe a que este es un subdominio en mi servidor o qué. Aquí está mi 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" );
                        }
                      }
                    });
                  });
                });

Así que configuré un ancla para ir a mi API en lugar de hacer una solicitud de publicación, que es lo que supongo que hacen la mayoría de las aplicaciones.

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

Debe incluir un campo de token CSRF oculto (falsificación de solicitud entre sitios) en el formulario para que el middleware de protección CSRF pueda validar la solicitud.

Laravel genera automáticamente un "token" CSRF para cada sesión de usuario activa administrada por la aplicación. Este token se usa para verificar que el usuario autenticado es el que realmente hace las solicitudes a la aplicación.

Entonces, al hacer solicitudes ajax, deberá pasar el token csrf a través del parámetro de datos. Aquí está el código de muestra.

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

Solo uso @csrf dentro del formulario y funciona bien

yo mismo
fuente