2016-11-10 218 views
7
我使用JQuery與ASP.NET核心1.0.1

啓用防僞令牌和我有Ajax調用:與ASP.NET核心和JQuery

$("#send-message").on("submit", function (event) { 
    event.preventDefault(); 
    var $form = $(this); 
    $.ajax({ 
    url: "api/messages", 
    data: JSON.stringify($form.serializeToJSON()), 
    dataType: "json", 
    headers: { 
     Accept: "application/json", 
     "Content-Type": "application/json" 
    }, 
    type: "post" 
    }) 
    .done(function (data, status, xhr) { }) 
    .fail(function (xhr, status, error) { }); 

到ASP.NET核心作用:

[HttpPost("messages")] 
public async Task<IActionResult> Post([FromBody]MessagePostApiModelModel model) { 
    // Send message 
} 

形式是在共享視圖,它是:

<form id="send-question" method="post"> 
    <textarea name="content"></textarea> 
    <button class="button" type="submit">Enviar</button> 
</form> 

當我提交表單我得到的錯誤:

Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery header value "RequestVerificationToken" is not present. 

如何使用JQuery Ajax調用啓用ASP.NET Core的AntiForgeryToken?

UPDATE

我需要將以下ASP-控制器和ASP的操作添加到形式:

<form asp-controller="QuestionApi" asp-action="Post" id="send-question" method="post"> 
</form> 

這將生成防僞標記。我需要手動添加標記到JQuery調用的標頭,如下所示:

headers: { 
    "Accept": "application/json", 
    "Content-Type": "application/json", 
    "RequestVerificationToken": $form.find("input[name='af_token']").val() 
    }, 

有沒有更好的方法來做到這一點?

如何解決這個問題,當沒有形式,我只有一個A標籤,當點擊使Ajax調用?我可以在我的頁面頭上生成一個通用的防僞標記,以供來自該頁面的所有ajax調用使用嗎?

+1

您的表單是否使用表單標籤助手生成服務器端?如果是這種情況,令牌已經作爲[隱藏輸入](http://stackoverflow.com/questions/30959972/html-antiforgerytoken-still-required)字段自動生成,所以它將被包含在' form.serializeToJSON'。無論答案如何,您還需要控制器操作中的[ValidateAntiForgeryToken]屬性。 –

+0

@ DanielJ.G。它是生成服務器端,但我沒有使用asp-controller和asp-action,因爲我使用JQuery提交它。我只是更新我的問題。我錯過了什麼嗎? –

+0

我需要在我的JQuery調用中手動添加以下頭文件:頭文件:{「RequestVerificationToken」:$ form.find(「input [name ='af_token]」)。val() },...有更好的辦法? –

回答

10

mode777的回答只需要一個小的添加,使這項工作(我試過) :

$(document).ajaxSend(function(e, xhr, options) { 
    if (options.type.toUpperCase() == "POST") { 
     var token = $form.find("input[name='af_token']").val(); 
     xhr.setRequestHeader("RequestVerificationToken", token); 
    } 
}); 

其實,如果你使用Ajax也提交,你不需要使用的一種形式都沒有。加入給你的JavaScript的

<span class="AntiForge"> @Html.AntiForgeryToken() </span> 

然後你皮卡令牌:

$(document) 
    .ajaxSend(function (event, jqxhr, settings) { 
     if (settings.type.toUpperCase() != "POST") return; 
     jqxhr.setRequestHeader('RequestVerificationToken', $(".AntiForge" + " input").val()) 
}) 

的@HtmlAntiForgeryToken生成帶有防僞標記的隱藏輸入字段,同樣在你_layout 將這個就像在使用表單時一樣。上面的代碼發現它使用類選擇器來選擇範圍,然後獲取輸入字段以收集令牌並將其添加爲標題。

+0

檢查生成的令牌名稱,在asp.core 1.1中它是__RequestVerificationToken,因此您需要相應地更改name ='...' –

+1

關於@Pieter van Kampen的評論,請注意表單字段名稱以雙下劃線開始,但標題名稱不是。 – jmcilhinney

+0

有一種更簡單的方式來獲取該數據,而不需要將任何不必要的東西放入HTML文檔中,請參閱我的答案。 – ygoe

0

您可以註冊一個全局AJAX事件,將頭添加到不受此得到所有Ajax調用:

$(document).ajaxSend(function(e, xhr, options) { 
    if (options.type.toUpperCase() != "GET") { 
     xhr.setRequestHeader("RequestVerificationToken", token); 
    } 
}); 
3

注意:此答案適用於ASP.NET Core 2.0。它可能不適合舊版本。

下面是我通過ASPNET的源代碼挖一會兒後進行:

<script> 
    var data = { 
     yourData: "bla", 
     "__RequestVerificationToken": "@Context.GetAntiforgeryToken()" 
    }; 
    $.post("@Url.Action("ActionName")", data); 
</script> 

您可能會修改:

public static class HttpContextExtensions 
{ 
    public static string GetAntiforgeryToken(this HttpContext httpContext) 
    { 
     var antiforgery = (IAntiforgery)httpContext.RequestServices.GetService(typeof(IAntiforgery)); 
     var tokenSet = antiforgery.GetAndStoreTokens(httpContext); 
     string fieldName = tokenSet.FormFieldName; 
     string requestToken = tokenSet.RequestToken; 
     return requestToken; 
    } 
} 

你可以在這樣的視圖中使用它擴展方法以任何形式返回字段的名稱,例如, G。一個JSON片段。

+1

這似乎是比文檔中描述的注入和函數方法更好的方法,因爲在視圖中總是有一個Context對象,不需要額外的「東西」。 – Erikest