2015-02-09 93 views
17

我正在爲所有POST請求默認啓用CSRF保護的Laravel 5應用程序工作。我喜歡這種增加的安全性,所以我正在嘗試使用它。

在做出簡單的$.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); 
    } 
}); 
+0

難道我理解正確的,你想使你的數據對象有一個'_token'場? (例如,類似'options ['data'] ._ token = csrf_token'的東西?)一個工作請求的一個例子會很有幫助,如果你有的話。 – apsillers 2015-02-09 19:37:09

+0

是的,正好... – NightMICU 2015-02-09 19:38:56

+0

爲了使請求工作,我將不得不添加令牌直接發佈數據 - 所以'{id:userID,'_token':令牌}' – NightMICU 2015-02-09 19:41:04

回答

21

$.ajaxPrefilter的做法是一個很好的一個。不過,您不需要添加標題;您只需將屬性添加到data字符串。

提供數據作爲$.post的第二個參數,然後在預濾波器訪問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

+0

好的,我只能用'options ['data'] = options ['data'] +'&_token ='+ csrf_token;' - 這個點符號似乎不起作用。它看起來更好,任何想法可能是什麼問題? – NightMICU 2015-02-09 19:52:35

+0

@NightMICU我看到了;問題不在於點符號,而是jQuery在前置過濾器獲取它之前將數據對象轉換爲查詢字符串。我編輯過(但我沒有測試過,所以讓我知道它是否仍然中斷)。 – apsillers 2015-02-09 19:57:40

+0

看起來不錯!謝謝一堆! – NightMICU 2015-02-09 20:01:33

0

我認爲上述解決方案可能無法正常工作。當你這樣做:

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

從Laravel文檔:

例如,您可以將令牌存儲在「元」標記中:

一旦你創建了元標記,你可以指示像 jQuery的庫來標記添加到所有請求頭。這提供了簡單,你的基於AJAX的應用程序 方便CSRF保護:

$ .ajaxSetup({ 頭:{ 'X-CSRF-TOKEN':$( '元[NAME = 「CSRF令牌」]' ).attr('content') }});

因此,例如,你可以做如下的請求。

這個元標記添加到您的視圖:

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

這是一個示例腳本,你可以用Laravel通訊(當你點擊使用id =「一些-ID」的元素髮出請求,你可以在一個id =「result」的元素中看到響應):

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

一般來說,我同意Kornel建議的概念,除了一件事。

是的,Laravel的文檔建議使用$.ajaxSetup,但不建議使用,因爲此方法影響所有後續的ajax請求。爲每個請求設置ajax設置更爲正確。雖然你可以重新設置的東西:

所有後續Ajax調用使用任何功能將使用新的設置,除非單獨調用所重寫,直到$ .ajaxSetup()的

下一次調用如果您使用$.ajax(),則使用data財產或headers更方便。 Laravel允許CSRF令牌作爲請求參數或標題。

首先,添加以下meta標籤到視圖

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

Django documentation on CSRF給出了一個用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); 
     } 
    } 
}); 
相關問題