web-dev-qa-db-ja.com

jQueryはすべての$ .post()リクエストのデータにCSRFトークンを追加します

私はLaravel 5のアプリで作業しています。すべてのPOST要求に対してデフォルトでCSRF保護が有効になっています。それ。

簡単な$.post()リクエストを作成しているときに、必要なフォーム入力_'Illuminate\Session\TokenMismatchException'_がPOST=データから欠落しているため、__token_エラーを受け取りました。問題の$ .postリクエストの例:

_var userID = $("#userID").val();
$.post('/admin/users/delete-user', {id:userID}, function() {
// User deleted
});
_

CSRFトークンをヘッダーのメタフィールドとして保存し、次を使用して簡単にアクセスできます。

_var csrf_token = $('meta[name="csrf-token"]').attr('content');
_

すべての発信$.post()リクエストでJSONデータにこれを追加することは可能ですか?ヘッダーを使用してみましたが、Laravelはヘッダーを認識していないようです-

_var csrf_token = $('meta[name="csrf-token"]').attr('content');
alert(csrf_token);
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
    if (options['type'].toLowerCase() === "post") {
        jqXHR.setRequestHeader('X-CSRFToken', csrf_token);
    }
});
_
23
NightMICU

あなたの$.ajaxPrefilterアプローチは良い方法です。ただし、ヘッダーを追加する必要はありません。プロパティをdata文字列に追加するだけです。

データは$.postの2番目の引数として提供され、プレフィルターがdataオプションにアクセスする前にクエリ文字列(id=foo&bar=baz&...)としてフォーマットされます。したがって、クエリ文字列に独自のフィールドを追加する必要があります。

var csrf_token = $('meta[name="csrf-token"]').attr('content');
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
    if (options.type.toLowerCase() === "post") {
        // initialize `data` to empty string if it does not exist
        options.data = options.data || "";

        // add leading ampersand if `data` is non-empty
        options.data += options.data?"&":"";

        // add _token entry
        options.data += "_token=" + encodeURIComponent(csrf_token);
    }
});

これにより、id=userIDid=userID&_token=csrf_tokenに変わります。

25
apsillers

From Laravel documentation:

たとえば、トークンを「メタ」タグに保存できます。

メタタグを作成したら、jQueryなどのライブラリに、すべてのリクエストヘッダーにトークンを追加するように指示できます。これにより、AJAXベースのアプリケーションにシンプルで便利なCSRF保護が提供されます。

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

たとえば、次のようなリクエストを行うことができます。

ビューにこのメタタグを追加します。

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

これは、Laravel(id = "some-id"の要素をクリックするとリクエストを送信し、id = "の要素で応答を確認できるスクリプト例です。結果"):

<script type="text/javascript">
    $(document).ready(function(){

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

        $("#some-id").on("click", function () {
            var request;


            request = $.ajax({
                url: "/your/url",
                method: "POST",
                data:
                {
                    a: 'something',
                    b: 'something else',
                },
                datatype: "json"
            });

            request.done(function(msg) {
                $("#result").html(msg);
            });

            request.fail(function(jqXHR, textStatus) {
                $("#result").html("Request failed: " + textStatus);
            });
        });

    });
</script>
18
Kornel

一般的に、Kornelが提案したコンセプトに同意しますが、1つだけあります。

はい、Laravelの_$.ajaxSetup_を使用するようにアドバイスしていますが、この方法は後続のすべてのAjaxリクエストに影響するためお勧めしません。各リクエストにajax設定を設定する方がより正確です。ものをリセットできますが:

関数を使用する後続のすべてのAjax呼び出しは、$。ajaxSetup()の次の呼び出しまで、個々の呼び出しによってオーバーライドされない限り、新しい設定を使用します

$.ajax()を使用する場合は、dataプロパティまたはheadersを使用する方が便利です。 Laravelは、CSRFトークンを要求パラメーターまたはヘッダーの両方として許可します。

最初に、次のメタタグをビューに追加します

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

そして、いずれかの方法でajaxリクエストを作成します。

_$.ajax({
    url: "/your/url",
    method: "POST",
    data:
    {
        a: 'something',
        b: 'something else',
        _token: $('meta[name="csrf-token"]').attr('content')
    },
    datatype: "json"
});
_

OR

_$.ajax({
    url: "/your/url",
    method: "POST",
    data:
    {
        a: 'something',
        b: 'something else',
    },
    headers: 
    {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
    datatype: "json"
});
_
7
Alex Baklanov

CSRFに関するDjangoのドキュメント は、重要なすべてのリクエストタイプに適切なヘッダーを自動的に追加するためのajaxSetupを持つニースコードスニペットを提供します。

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});
5
phk

これを行うにはもっと簡単な方法があります。送信する前にデータをシリアル化できます

<form method="post" id="formData">
 <input type="text" name="name" >
 <input type="hidden" name="_token" value="{{ csrf_token() }}">
 <input type="submit" id="sub" class="btn btn-default" value="Submit" />                            
</form>
<script>
    $(document).on('submit', '#formData', function (event) {
    event.preventDefault();
     var formData = $('#formData').serialize();
    $.ajax({
        url: url,
       type: "POST",
       data : formData,   
                success: function (result) {
                    console.log(result);                             
                }
           });
        });

    });
</script>

名前がattrのすべてのものがクエリに入力され、送信されます

0
c319113

上記の解決策もうまく機能しない可能性があると思います。行うとき:

var x; 
x + ""
// "undefined" + empty string coerces value to string 

「undefined_token = xxx」のようなデータを取得します

たとえば、上記のソリューションをlaravelの削除に使用する場合、次のように確認する必要があります。

if (typeof options.data === "undefined")
    options.data = "";
else
    options.data += "&";
options.data = "_token=" + csrf_token;
0