ASP.NET Core MVC防伪

And*_*tin 4 asp.net asp.net-mvc antiforgerytoken asp.net-core

试图在核心mvc项目中打开防伪,但没有运气.做了什么:

添加过滤器以自动检查每个POST请求上的防伪标记.

services.AddMvc(o =>
{
  o.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Run Code Online (Sandbox Code Playgroud)

令牌生成以这种方式添加到每个页面.

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery;
@{
   var antiforgeryRequestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
...
...
<script>
    var antiforgeryToken = @Json.Serialize(antiforgeryRequestToken);
</script>
Run Code Online (Sandbox Code Playgroud)

最后每个客户端ajax请求都添加了RequestVerificationToken这种方式.

var options = {
        url: o.url, type: 'POST', data: o.params, headers: { 'RequestVerificationToken': antiforgeryToken } };
Run Code Online (Sandbox Code Playgroud)

我可以看到每个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");
Run Code Online (Sandbox Code Playgroud)

这是注册的中间件:

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); 
});
Run Code Online (Sandbox Code Playgroud)

我还删除了之前发送标头的任何客户端javascript代码.但它仍然无效.

Tra*_*man 10

你很亲密,它比你想象的要简单得多.

首先,当你使用services.AddMvc();防伪时已经添加了.无需添加任何过滤器,因此请删除它们.

然后你会想要改变你的防伪配置.

// Old
services.AddAntiforgery(o => o.CookieName = "XSRF-TOKEN"); 
// New
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
Run Code Online (Sandbox Code Playgroud)

只有在使用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");
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

重要的是beforeSend功能.这是您在设置中将请求标头设置为相同标头名称的位置Startup.cs

现在您需要做的就是添加[ValidateAntiForgeryToken]您想要的方法.

最后在测试之前一定要删除你添加的中间件.

这只是一种方法.还有在官方文档中发现许多其他解决方案在这里.