2010-02-28 65 views
8

我正在構建的頁面在很大程度上取決於AJAX。基本上,只有一個「頁面」,每個數據傳輸都是通過AJAX處理的。由於瀏覽器端的過度優化緩存會導致奇怪的問題(數據未重新載入),所以我必須使用POST執行所有請求(也讀取) - 這會強制重新加載。使用MVC2的AJAX請求中的CSRF保護

現在我想阻止頁面對CSRF。使用表單提交,使用Html.AntiForgeryToken()工作整齊,但在AJAX請求中,我想我將不得不手動追加令牌?有沒有什麼可用的盒子?

我當前的嘗試看起來像這樣

我很想重用現有的魔力。然而,HtmlHelper.GetAntiForgeryTokenAndSetCookie是私人的,我不想在MVC中破解。另一個選擇是寫一個擴展名,如

public static string PlainAntiForgeryToken(this HtmlHelper helper) 
{ 
    // extract the actual field value from the hidden input 
    return helper.AntiForgeryToken().DoSomeHackyStringActions(); 
} 

這是有點hacky,並留下更大的問題未解決:如何驗證令牌?默認驗證實現是內部的,並且使用表單字段進行硬編碼。我試圖寫一個稍微修改的ValidateAntiForgeryTokenAttribute,但它使用了一個私人的AntiForgeryDataSerializer,我真的不想複製它。

在這一點上,想出一個本土解決方案似乎更容易,但這實際上是重複的代碼。

任何建議如何做到這一點的聰明方式?我錯過了一些完全明顯的東西?

回答

10

你可以使用傳統的Html.AntiForgeryToken()幫手產生某處在頁面上隱藏字段(不一定是表單中),幷包括沿Ajax請求:

var token = $('input[name=__RequestVerificationToken]').val(); 
$.post(
    '/SomeAction', { '__RequestVerificationToken': token }, 
    function() { 
     alert('Account Deleted.'); 
    } 
); 

爲了驗證它在服務器端:

[AcceptVerbs(HttpVerbs.Post)] 
[ValidateAntiForgeryToken] 
public ActionResult SomeAction() 
{ 
    return View(); 
} 

如果您的頁面上有多個標記,則可能需要指定要包含哪個標記。由於現有的助手生成具有相同名稱的隱藏字段,很難做出好的選擇,所以你可以將它們放在裏面跨度:

<span id="t1"><%= Html.AntiForgeryToken() %></span> 
<span id="t2"><%= Html.AntiForgeryToken() %></span> 

,然後選擇相應的記號:

var token = $('#t1 input[name=__RequestVerificationToken]').val(); 
+0

輝煌!奇蹟般有效!我不知道發佈的字段會在'Request.Form'中結束。 +1非常整潔的選擇語句。乾杯! – mnemosyn 2010-02-28 14:24:06