Невідповідність маркера csrf Laravel для запиту POST Ajax


114

Я намагаюся видалити дані з бази даних через ajax.

HTML:

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

Мій код 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;
}
});

Це мій запит для отримання даних із бази даних ...

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

Але коли я натискаю Видалити дані посилання не видаляються і показує невідповідність csrf_token ...



ви повинні додати успіх і помилку в свій код ajax. помилка покаже проблему. stackoverflow.com/questions/45668337 / ...
Реза Джафарі

Відповіді:


176

Ви повинні додати дані у своєму запиті ajax. Я сподіваюся, це буде робота.

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

32
Що робити, якщо функція ajax знаходиться у .jsфайлі?
Бране

1
Це не працює на Laravel 5.7. Відповідь zarpio правильна.
Омар Мурсія

1
@Brane надсилає маркер як параметр у функції
Абделалім Хассуна

Це не працює в Laravel 5.8. Він все ще говорить про невідповідність символів. Перевірте мою відповідь нижче для простого рішення
Gjaa

чи змінює laravel маркер csrf після запиту json? вам потрібно відправити новий на головну сторінку?
davefrassoni

185

Найкращий спосіб вирішити цю проблему "X-CSRF-TOKEN" - це додати такий код до свого основного макета і продовжувати нормально здійснювати дзвінки ajax:

У заголовку

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

За сценарієм

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

5
Спасибі людина. Це більш досконале рішення! Таким чином ви просто налаштуєте його один раз, а потім просто продовжите писати свій звичайний код $ .ajax.
pkid169

4
Це найкраще рішення, оскільки ви можете використовувати його всередині .jsфайлів
Адам,

3
На сьогодні найкраща відповідь. Дякую.
Пол Денисевич

а якщо "глобальний: помилковий"?
Мішель,

1
Як csrf можна оновлювати після кожного дзвінка? перший дзвінок чудово працює, підпослідовні дзвінки не працюють через маркер CSRF.
Jjsg08,

28

Я думаю, що краще помістити маркер у форму, і отримати цей маркер за ідентифікатором

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

І JQUery:

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

таким чином, ваш JS не повинен бути у ваших файлах леза.


25

Я щойно додав headers:у дзвінку ajax:

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

з огляду:

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

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

функція 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>

в контролері:

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

у маршрутах.php

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

1
додавання заголовків до виклику ajax мені допомогло.
Chaudhry Waqas

1
Це найкраща відповідь, оскільки для цього не потрібно, щоб JavaScript знаходився у файлі леза (якщо ви не хочете, щоб він був у файлі леза, але тоді він відображається кожного разу, коли хтось заходить на цю сторінку)
Zachary Weixelbaum,

11

Якщо ви використовуєте файли шаблонів, тоді ви можете помістити свій metaтег в голову section(або як би ви його не називали), який містить ваші metaтеги.

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

Наступне, вам потрібно додати headersатрибут до вашого ajax(у моєму прикладі я використовую datatableз обробкою на стороні сервера:

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

Ось повний datatableприклад 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);
           }
        }
    });

Після цього вам слід отримати 200 statusдля вашого ajaxзапиту.


6

Знайте, що існує файл cookie X-XSRF-TOKEN, який встановлений для зручності. Такі фреймворки, як Angular та інші, встановлюють його за замовчуванням. Перевірте це в документі https://laravel.com/docs/5.7/csrf#csrf-x-xsrf-token Вам може сподобатися ним скористатися.

Найкращий спосіб - використовувати мета, якщо файли cookie деактивовані.

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

Ось рекомендований мета-спосіб (поле можна розмістити будь-яким способом, але мета тихо-приємно):

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

Зверніть увагу на використання decodeURIComponent(), це декодування з формату uri, який використовується для зберігання файлів cookie. [інакше ви отримаєте недійсний виняток корисного навантаження в laravel].

Ось розділ про файл cookie csrf у документі для перевірки: https://laravel.com/docs/5.7/csrf#csrf-x-csrf-token

Також тут, як laravel (bootstrap.js) встановлює його для 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');
} 

Ви можете піти перевірити resources/js/bootstrap.js.

А тут прочитайте функцію 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

Додайте елемент idдо metaелемента, що містить маркер

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

І тоді ви можете отримати його у своєму Javascript

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

1
Якщо ви не хочете додавати ідентифікатор, просто використовуйте: $ ("[name = csrf-token]"). Attr ("content"). Він отримає потрібний елемент за атрибутом name.
Педро Соуса,

3

якщо ви використовуєте jQuery для надсилання повідомлень AJAX, додайте цей код у всі подання:

$( 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 додає файл cookie XSRF до всіх запитів, і ми автоматично додаємо його до всіх запитів AJAX безпосередньо перед поданням.

Ви можете замінити функцію getCookie, якщо є інша функція або плагін jQuery, щоб зробити те саме.


1

Для Laravel 5.8 встановлення мета-тегу csrf для вашого макета та встановлення заголовка запиту для csrf у налаштуваннях ajax не буде працювати, якщо ви використовуєте ajax для надсилання форми, яка вже містить _token поле введення, створене механізмом шаблонування леза Laravel.

Ви повинні включити вже згенерований маркер csrf із форми до вашого запиту ajax, оскільки сервер очікував би цього, а не того, що міститься у вашому метатегу.

Наприклад, так виглядає _tokenполе введення, сформоване Blade:

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

Потім ви подаєте свою форму за допомогою ajax таким чином:

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

Маркер csrf у мета-заголовку корисний лише тоді, коли ви надсилаєте форму без _tokenполя введення, створеного Blade .


1

хто коли-небудь отримує проблему з прийнятою відповіддю @Deepak saini, спробуйте видалити

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

для дзвінка ajax.

використання

dataType:"json",

0

Я насправді мав цю помилку і не міг знайти рішення. Я фактично закінчив не робити запит ajax. Я не знаю, чи ця проблема була пов’язана з тим, що це субдомен на моєму сервері, чи що. Ось мій 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" );
                        }
                      }
                    });
                  });
                });

Тому я фактично встановив прив'язку, щоб переходити до мого API, а не робити запит на публікацію, що, на мою думку, робить більшість програм.

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

0

Ви повинні включити у форму поле маркера прихованого CSRF (підроблення запиту між сайтами), щоб захистити CSRF проміжне програмне забезпечення могло перевірити запит.

Laravel автоматично генерує "маркер" CSRF для кожного активного сеансу користувача, керованого додатком. Цей маркер використовується для підтвердження того, що автентифікований користувач є тим, хто насправді робить запити до програми.

Отже, роблячи запити ajax, вам потрібно буде передати маркер csrf через параметр data. Ось зразок коду.

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

0

Я просто використовую @csrf всередині форми та працює нормально

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.