2016-11-10 138 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