Ajax POSTリクエストのLaravel csrfトークンの不一致


112

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/...
レザjafari

回答:


175

ajaxリクエストにデータを追加する必要があります。うまくいくことを願っています。

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

32
ajax関数が.jsファイルにある場合はどうなりますか?
Brane

1
Laravel 5.7では動作しません。zarpioの答えは正しいです。
オマールムルシア

1
@Braneは関数
内のパラメーター

これはLaravel 5.8では機能しません。それでもトークンの不一致が表示されます。簡単な解決策については、以下の私の答えを確認してください
Gjaa

laravelはjsonリクエスト後にcsrfトークンを変更しますか?新しいものをメインページに送る必要がありますか?
davefrassoni

182

この問題「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 2017

4
.jsファイル内で使用できるため、これはより良いソリューションです
Adam

3
これまでのベストアンサー。ありがとう。
ポールデニセビッチ2018

「global:false」の場合はどうなりますか?
ミシェル

呼び出しごとにcsrfをどのように更新できますか?最初の呼び出しは適切に機能し、後続の呼び出しはCSRFトークンが原因で失敗します。
Jjsg08

28

トークンをフォームに入れて、このトークンをIDで取得する方が良いと思います

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

routes.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')}

これが完全なdatatableajaxの例です:

$('#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

便宜上設定されたX-XSRF-TOKEN Cookieがあることを確認してください。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()。これは、Cookieの保存に使用されるURI形式からのデコードです。[そうしないと、laravelで無効なペイロード例外が発生します]。

ここで、チェックするドキュメントのcsrf Cookieに関するセクション: https

また、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

そしてここでクッキー関数を読んでください:

   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

追加idmetaトークンを保持している要素

<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
IDを追加したくない場合は、代わりに$( "[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はすべてのリクエストにXSRF Coo​​kieを追加し、送信直前にすべてのAJAXリクエストに自動的に追加します。

同じことを行う別の関数またはjQueryプラグインがある場合は、getCookie関数を置き換えることができます。


1

Laravel 5.8の場合、レイアウトにcsrfメタタグを設定し、ajax設定でcsrfのリクエストヘッダーを設定_tokenしても、Laravelブレードテンプレートエンジンによって生成された入力フィールドがすでに含まれているフォームをajaxを使用して送信する場合は機能しません。

サーバーがメタタグのトークンではなく、トークンを予期しているため、フォームからすでに生成されたcsrfトークンをajaxリクエストに含める必要があります。

たとえば、_tokenBladeによって生成された入力フィールドは次のようになります。

<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トークンは、Bladeで生成された_token入力フィールドなしでフォームを送信する場合にのみ役立ちます。


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トークンを渡す必要があります。これがサンプルコードです。

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

0

私はフォーム内で@csrfを使用し、その正常に機能します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.