试图在核心MVC项目中打开防伪功能,但是没有运气。做了什么:
添加了过滤器,以便在每个POST请求中自动检查防伪令牌。
services.AddMvc(o =>
{
o.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
令牌生成以这种方式添加到每个页面。
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery;
@{
var antiforgeryRequestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
...
...
<script>
var antiforgeryToken = @Json.Serialize(antiforgeryRequestToken);
</script>
最后,每个客户端ajax请求都以这种方式添加
RequestVerificationToken
。var options = {
url: o.url, type: 'POST', data: o.params, headers: { 'RequestVerificationToken': antiforgeryToken } };
我可以看到每个ajax请求都具有令牌,但是对于任何POST请求,我总是得到400。如果我禁用了过滤器,则可以正常工作。但是,一旦启用它,asp.net核心将在每个POST请求上开始验证,并且始终返回400。
有任何想法吗?
更新:
我按照注释中的说明进行操作,现在代码如下。 ConfigureServices方法:
services.AddMvc(o => {
o.Filters.Add(new HandleAllExceptionsFilterFactory());
o.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
services.AddAntiforgery(o => o.CookieName = "XSRF-TOKEN");
这是注册的中间件:
app.Use(next => context => {
if (context.Request.Path == "/")
{
var antiforgery = app.ApplicationServices.GetService<IAntiforgery>();
var token = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", token.RequestToken, new CookieOptions {HttpOnly = false});
}
return next(context);
});
我还删除了之前已发送标头的所有客户端javascript代码。但这仍然行不通。
最佳答案
您接近了,比您想象的要简单得多。
首先,当您使用services.AddMvc();
时,已经添加了防伪。无需添加任何过滤器,因此请删除这些过滤器。
然后,您将需要更改防伪配置。
// Old
services.AddAntiforgery(o => o.CookieName = "XSRF-TOKEN");
// New
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
仅在使用ajax时才需要。默认情况下,防伪系统将仅考虑表单数据。
接下来,在您的视图中,您可以使用
@Html.AntiForgeryToken()
轻松生成防伪令牌。不需要所有这些额外的代码。您可以摆脱它。这将使用令牌的值创建一个隐藏的<input />
。如果您使用<form />
,并且使用asp-action
和asp-controller
之类的标记帮助器,则会自动为您创建。如果您不使用这些标记助手,则可以使用asp-antiforgery="true"
。现在,您的ajax请求可以使用隐藏的
<input />
值。这是一个例子:$.ajax({
method: "POST",
url: "/api/test",
data: data,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
statusCode: {
200: function () {
alert("Success");
},
400: function () {
alert("Client error");
},
500: function () {
alert("Server error");
}
}
});
重要的部分是
beforeSend
函数。在这里,您可以在Startup.cs
中设置请求标头为相同的标头名称现在,您需要做的就是将
[ValidateAntiForgeryToken]
添加到所需的方法中。最后,在测试之前,请确保删除添加的中间件。
这只是做到这一点的一种方法。在官方文档here中找到了许多其他解决方案。