Laravel csrf token mismatch para ajax POST Request

113

Estou tentando excluir dados do banco de dados 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

Meu 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 é minha consulta para buscar dados do banco de dados ...

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

Mas quando clico em Excluir dados de link não excluídos e mostro incompatibilidade csrf_token ...

Ashish Singh
fonte
você deve adicionar sucesso e erro ao seu código Ajax. o erro mostrará o problema. stackoverflow.com/questions/45668337/…
reza jafari

Respostas:

176

Você deve adicionar dados em sua solicitação ajax. Espero que dê certo.

data: {
        "_token": "{{ csrf_token() }}",
        "id": id
        }
Deepak Saini
fonte
32
E se a função ajax estiver localizada no .jsarquivo?
Brane
1
Não funciona no Laravel 5.7. A resposta de zarpio está correta.
Omar Murcia
1
@Brane envia o token como um parâmetro na função
Abdelalim Hassouna
Isso não funciona no Laravel 5.8. Ele ainda indica incompatibilidade de token. Verifique minha resposta abaixo para uma solução simples
Gjaa
o laravel altera o token csrf após uma solicitação json? você precisa enviar o novo para a página principal?
davefrassoni
184

A melhor maneira de resolver este problema "X-CSRF-TOKEN" é adicionar o seguinte código ao seu layout principal e continuar fazendo suas chamadas ajax normalmente:

No cabeçalho

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

No script

<script type="text/javascript">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
</script>
Zarpio
fonte
5
Obrigado cara. Esta é uma solução mais completa! Dessa forma, você apenas configura uma vez e, a partir daí, começa a escrever seu código $ .ajax normal.
pkid169
4
Esta é a melhor solução porque você pode usá-la dentro de .jsarquivos
Adam
3
Melhor resposta até agora. Obrigado.
Paul Denisevich
e se "global: false"?
Michel
1
Como o csrf pode ser atualizado após cada chamada? a primeira chamada funciona bem, as chamadas subsequentes falham devido ao token CSRF.
Jjsg08 01 de
28

Acho melhor colocar o token no formulário, e pegar esse token por id

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

E o JQUery:

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

dessa forma, seu JS não precisa estar em seus arquivos blade.

cmnardi
fonte
25

Acabei de adicionar headers:na chamada ajax:

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

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

função 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>

no controlador:

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

em routes.php

Route::post('ajax', 'AjaxController@call');
Lewis4u
fonte
1
adicionar cabeçalhos à chamada ajax me ajudou.
Chaudhry Waqas,
1
Esta é a melhor resposta porque não requer que o JavaScript esteja em um arquivo blade (a menos que você queira em um arquivo blade, mas ele está sendo renderizado toda vez que alguém
acessa
11

Se você estiver usando arquivos de modelo, então você pode colocar sua metatag no cabeçalho section(ou qualquer que seja o nome) que contém suas metatags.

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

Em seguida, você precisa colocar o headersatributo em seu ajax(no meu exemplo, estou usando datatablecom processamento do lado do servidor:

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

Aqui está o datatableexemplo 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);
           }
        }
    });

Depois de fazer isso, você deverá atender 200 statusao seu ajaxpedido.

Brane
fonte
6

Saiba que existe um cookie X-XSRF-TOKEN configurado para sua conveniência. Framework como Angular e outros o definem por padrão. Verifique isso no documento https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token. Você pode gostar de usá-lo.

A melhor forma é usar o meta, caso os cookies estejam desativados.

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

Aqui está o método meta recomendado (você pode colocar o campo de qualquer maneira, mas o meta é muito bom):

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

Observe o uso de decodeURIComponent(), é decodificado do formato uri que é usado para armazenar o cookie. [caso contrário, você obterá uma exceção de carga útil inválida no laravel].

Aqui está a seção sobre o cookie csrf no documento para verificar: https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

Também aqui como laravel (bootstrap.js) está configurando para axios por padrão:

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

você pode ir verificar resources/js/bootstrap.js.

E aqui leia a função do 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
fonte
5

Adicione um idao metaelemento que contém o token

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

E então você pode obtê-lo em seu Javascript

$.ajax({
  url : "your_url",
  method:"post",
  data : {
    "_token": $('#csrf-token')[0].content  //pass the CSRF_TOKEN()
  },  
  ...
});
Gjaa
fonte
1
Se você não quiser adicionar um id, basta usar: $ ("[name = csrf-token]"). Attr ("content") ao invés. Ele irá buscar o elemento certo pelo atributo name.
Pedro Sousa
3

se você estiver usando jQuery para enviar Postagens AJAX, adicione este código a todas as visualizações:

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

O Laravel adiciona um cookie XSRF a todas as solicitações, e nós o anexamos automaticamente a todas as solicitações AJAX antes de enviar.

Você pode substituir a função getCookie se houver outra função ou plugin jQuery para fazer a mesma coisa.

AMIB
fonte
1

Para o Laravel 5.8, definir a meta tag csrf para o seu layout e definir o cabeçalho da solicitação para csrf nas configurações do ajax não funcionará se você estiver usando o ajax para enviar um formulário que já inclui um _token campo de entrada gerado pelo motor de templates do Laravel.

Você deve incluir o token csrf já gerado do formulário com sua solicitação ajax porque o servidor estaria esperando por ele e não aquele em sua metatag.

Por exemplo, é assim que o _tokencampo de entrada gerado pelo Blade se parece:

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

Em seguida, você envia seu formulário com ajax como este:

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

O token csrf no meta cabeçalho só é útil quando você está enviando um formulário sem um _tokencampo de entrada gerado pelo Blade .

Udo E.
fonte
1

quem está tendo problemas com a resposta aceita @Deepak saini, tente remover

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

para chamada ajax.

usar

dataType:"json",
Mrudul Addipalli
fonte
0

Na verdade, tive esse erro e não consegui encontrar uma solução. Na verdade, acabei não fazendo uma solicitação ajax. Não sei se este problema foi devido a ser um subdomínio no meu servidor ou o quê. Aqui está meu 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" );
                        }
                      }
                    });
                  });
                });

Então, na verdade, configurei uma âncora para ir para minha API em vez de fazer uma solicitação de postagem, que é o que eu acho que a maioria dos aplicativos faz.

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

Você deve incluir um campo de token CSRF (falsificação de solicitação entre sites) oculto no formulário para que o middleware de proteção CSRF possa validar a solicitação.

O Laravel gera automaticamente um "token" CSRF para cada sessão de usuário ativa gerenciada pelo aplicativo. Esse token é usado para verificar se o usuário autenticado é quem realmente faz as solicitações ao aplicativo.

Portanto, ao fazer solicitações ajax, você precisará passar o token csrf por meio do parâmetro de dados. Aqui está o código de amostra.

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

Acabei de usar @csrf dentro do formulário e está funcionando bem

Eu mesmo
fonte