试图在核心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-actionasp-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中找到了许多其他解决方案。

10-04 16:37