Niezgodność tokena Laravel CSRF dla żądania AJAX POST

114

Próbuję usunąć dane z bazy danych za pośrednictwem AJAX.

HTML:

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

Mój kod 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;
}
});

To jest moje zapytanie o pobranie danych z bazy danych ...

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

Ale kiedy kliknę Usuń dane łącza, które nie zostały usunięte i pokażę niezgodność csrf_token ...

Ashish Singh
źródło
powinieneś dodać sukces i błąd do swojego kodu AJAX. błąd pokaże problem. stackoverflow.com/questions/45668337/…
reza jafari

Odpowiedzi:

177

Musisz dodać dane w swoim żądaniu Ajax. Mam nadzieję, że tak będzie.

data: {
        "_token": "{{ csrf_token() }}",
        "id": id
        }
Deepak saini
źródło
32
Co się stanie, jeśli funkcja Ajax znajduje się w .jspliku?
Brane
1
Nie działa na Laravel 5.7. Odpowiedź zarpio jest prawidłowa.
Omar Murcia
1
@Brane wysyła token jako parametr w funkcji
Abdelalim Hassouna
To nie działa w Laravel 5.8. Nadal pokazuje niezgodność tokenu. Sprawdź moją odpowiedź poniżej, aby uzyskać proste rozwiązanie
Gjaa
czy laravel zmienia token csrf po żądaniu json? czy musisz wysłać nowy na stronę główną?
davefrassoni
187

Najlepszym sposobem rozwiązania tego problemu „X-CSRF-TOKEN” jest dodanie następującego kodu do głównego układu i kontynuowanie normalnego wykonywania wywołań Ajax:

W nagłówku

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

W skrypcie

<script type="text/javascript">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
</script>
zarpio
źródło
5
Dzięki. To bardziej wszechstronne rozwiązanie! W ten sposób konfigurujesz go tylko raz, a potem po prostu zapisujesz swój normalny kod $ .ajax.
pkid169
4
Jest to lepsze rozwiązanie, ponieważ można go używać w .jsplikach
Adam
3
Jak dotąd najlepsza odpowiedź. Dzięki.
Paul Denisevich,
co, jeśli „global: false”?
Michel,
1
Jak można aktualizować csrf po każdym połączeniu? pierwsze wywołanie działa świetnie, kolejne wywołania zawodzą z powodu tokena CSRF.
Jjsg08
28

Myślę, że lepiej umieścić token w formularzu i uzyskać ten token przez id

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

A JQUery:

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

w ten sposób Twój JS nie musi znajdować się w plikach blade.

cmnardi
źródło
25

Właśnie dodałem headers:w wywołaniu Ajax:

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

z uwagi:

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

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

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

w kontrolerze:

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

w route.php

Route::post('ajax', 'AjaxController@call');
lewis4u
źródło
1
dodanie nagłówków do wywołania Ajax pomogło mi.
Chaudhry Waqas
1
To najlepsza odpowiedź, ponieważ nie wymaga JavaScript, aby znajdować się w pliku blade (chyba że chcesz go w pliku blade, ale wtedy jest renderowany za każdym razem, gdy ktoś wejdzie na tę stronę)
Zachary Weixelbaum
12

Jeśli używasz plików szablonów, możesz umieścić swój metatag w nagłówku section(lub jakkolwiek go nazwiesz), który zawiera Twoje metatagi.

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

Następnie musisz headersprzypisać atrybut do swojego ajax(w moim przykładzie używam datatablez przetwarzaniem po stronie serwera:

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

Oto pełny datatableprzykład 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);
           }
        }
    });

Po wykonaniu tej czynności powinieneś dostać się 200 statusna swoją ajaxprośbę.

Brane
źródło
6

Wiedz, że istnieje plik cookie X-XSRF-TOKEN, który jest ustawiony dla wygody. Framework taki jak Angular i inni ustawiają go domyślnie. Sprawdź to w dokumencie https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token Możesz go użyć.

Najlepszym sposobem jest użycie meta, jeśli pliki cookie są dezaktywowane.

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

Tutaj zalecany sposób meta (możesz umieścić pole w dowolny sposób, ale meta jest cicha):

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

Zwróć uwagę na użycie decodeURIComponent(), dekoduje z formatu uri, który jest używany do przechowywania pliku cookie. [w przeciwnym razie w laravel pojawi się wyjątek dotyczący nieprawidłowego ładunku].

Tutaj sekcja dotycząca pliku cookie csrf w dokumencie do sprawdzenia: https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

Również tutaj, jak laravel (bootstrap.js) domyślnie ustawia go dla 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');
} 

możesz iść sprawdzić resources/js/bootstrap.js.

A tutaj przeczytaj funkcję 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
źródło
5

Dodaj an iddo metaelementu, który zawiera token

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

A potem możesz go pobrać w swoim Javascript

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

EDYCJA: Łatwiejszy sposób bez zmiany metalinii.

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

Lub

data : { 
    _token: @json(csrf_token()), 
}

Dzięki @ martin-hartmann

Gjaa
źródło
2
Jeśli nie chcesz dodawać identyfikatora, po prostu użyj: $ ("[name = csrf-token]"). Attr ("content"). Pobierze odpowiedni element według atrybutu nazwy.
Pedro Sousa
1
Możliwe jest również umieszczenie reklamy w polu danych: data: {"_token": "{{csrf_token ()}}" // przekazać CSRF_TOKEN ()},
Martin Hartmann
3

jeśli używasz jQuery do wysyłania postów AJAX, dodaj ten kod do wszystkich widoków:

$( 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 dodaje plik cookie XSRF do wszystkich żądań i automatycznie dołączamy go do wszystkich żądań AJAX tuż przed przesłaniem.

Możesz zastąpić funkcję getCookie, jeśli istnieje inna funkcja lub wtyczka jQuery, która robi to samo.

AMIB
źródło
1

Dla Laravel 5.8, ustawienie metatagu csrf dla twojego układu i ustawienie nagłówka żądania dla csrf w ustawieniach ajax nie zadziała, jeśli używasz Ajax do przesłania formularza, który już zawiera _tokenpole wejściowe wygenerowane przez silnik szablonów Laravel Blade.

Musisz dołączyć już wygenerowany token csrf z formularza do żądania AJAX, ponieważ serwer będzie go oczekiwał, a nie ten w tagu meta.

Na przykład tak wygląda _tokenpole wejściowe generowane przez Blade:

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

Następnie prześlij swój formularz za pomocą Ajax w następujący sposób:

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

Token csrf w nagłówku meta jest przydatny tylko wtedy, gdy przesyłasz formularz bez _tokenpola wejściowego wygenerowanego przez Blade .

Udo E.
źródło
1

kto kiedykolwiek ma problem z zaakceptowaną odpowiedzią @Deepak saini, spróbuj usunąć

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

dla połączenia AJAX.

posługiwać się

dataType:"json",
Mrudul Addipalli
źródło
0

Właściwie miałem ten błąd i nie mogłem znaleźć rozwiązania. W rzeczywistości nie wykonałem żądania Ajax. Nie wiem, czy ten problem był spowodowany tym, że jest to subdomena na moim serwerze, czy co. Oto moje 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" );
                        }
                      }
                    });
                  });
                });

Więc tak naprawdę skonfigurowałem kotwicę, aby przejść do mojego API, zamiast wykonywać żądanie posta, co, jak sądzę, robi większość aplikacji.

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

W formularzu należy uwzględnić ukryte pole tokenu CSRF (fałszowanie żądań między lokacjami), aby oprogramowanie pośredniczące ochrony CSRF mogło zweryfikować żądanie.

Laravel automatycznie generuje "token" CSRF dla każdej aktywnej sesji użytkownika zarządzanej przez aplikację. Ten token służy do weryfikacji, czy uwierzytelniony użytkownik jest tym, który faktycznie wysyła żądania do aplikacji.

Więc wykonując żądania Ajax, musisz przekazać token csrf poprzez parametr data. Oto przykładowy kod.

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

Po prostu używam @csrf wewnątrz formularza i działa dobrze

siebie
źródło