在ASP.NET Core中,如我我们希望用jQuery Ajax向服务器提交数据,并希望使用ValidateAntiForgeryToken标记,我们需要一些技巧。官方文档并没有说如何使用jQuery完成这个操作,我来演示给大家看看。
请首先阅读官方文档 https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1
在我的实践中,实际场景和官方文档有所区别。
01
Token 生成
首先,我们仍然需要一个隐藏input去存储CSRF token,官网的代码如下
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<input type="hidden" id="RequestVerificationToken"
name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">
我用了个更简单的方法
@Html.AntiForgeryToken()
这样做有些好处。首先,显然省去了几行代码。不过,最重要的是,因为我已经自定义了CSRF的名称,就像这样
services.AddAntiforgery(options =>
{
options.Cookie.Name = "X-CSRF-TOKEN-MOONGLADE";
options.FormFieldName = "CSRF-TOKEN-MOONGLADE-FORM";
});
后台的Controller会使用这些名称去验证请求,并且,我不希望忘记更改每一处手写的代码。所以,换句话说,@Html.AntiForgeryToken()会基于我在Startup.cs中的定义生成HTML代码。如果哪天我改了antiforgery options的名称,我不需要担心哪个cshtml文件里忘了做对应的修改。
<input name="CSRF-TOKEN-MOONGLADE-FORM" type="hidden" value="CfDJ8BBX[...]">
02
Controller和Action
这和普通的Action没有啥区别,只要加上[ValidateAntiForgeryToken]标记就够了
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
[Route("delete")]
public IActionResult Delete(Guid pingbackId)
{
...
}
03
jQuery 代码
这里是真正关键的地方,官网文档里的JavaScript代码值是给请求加了header
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("antiforgery").onclick = function () {
xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
xhttp.setRequestHeader("RequestVerificationToken",
document.getElementById('RequestVerificationToken').value);
xhttp.send();
}
});
我们在jQuery中同样也能实现
$.ajax({
...
headers: {
"CSRF-TOKEN-MOONGLADE-FORM": $('input[name="CSRF-TOKEN-MOONGLADE-FORM"]').val()
},
...
});
然而,这并不能工作。我还没搞明白为啥,但是我有了解决方法,就是把CSRF的值放到提交的数据中去。
我使用$.extend方法将“CSRF-TOKEN-MOONGLADE-FORM”加入
var pData = $.extend({ pingbackId: pingbackId },
{ "CSRF-TOKEN-MOONGLADE-FORM": $('input[name="CSRF-TOKEN-MOONGLADE-FORM"]').val()});
现在整段Ajax代码看起来就像这样
$(function () {
$(".btn-delete").click(function () {
deletePingback($(this).data("pingbackid"));
});
});
function deletePingback(pingbackId) {
$("#span-processing-" + pingbackId).show();
var pData = $.extend({ pingbackId: pingbackId }, { "CSRF-TOKEN-MOONGLADE-FORM": $('input[name="CSRF-TOKEN-MOONGLADE-FORM"]').val()});
$.ajax({
type: "POST",
url: "pingback/delete",
headers: {
"CSRF-TOKEN-MOONGLADE-FORM": $('input[name="CSRF-TOKEN-MOONGLADE-FORM"]').val()
},
data: pData,
success: function (data) {
$("#pingback-box-" + data).slideUp();
},
dataType: "json"
});
}
现在你的Ajax请求可以被后台MVC的action成功验证了。