ASP.NET Core React SPA 应用程序中的 ValidateAntiForgeryToken
ValidateAntiForgeryToken in an ASP.NET Core React SPA Application
我正在尝试使用框架的工具向 ASP.NET Core React SPA 添加一些简单的 CSRF 验证。该应用程序本身本质上是一个 create-react-app 设置(带有根元素的单个 index.html,其他所有内容都从捆绑的 JavaScript 中加载)。
修改在 this one 等链接上找到的一些信息,我在 Startup.ConfigureServices
中设置了以下内容:
services.AddAntiforgery(options => options.Cookie.Name = "X-CSRF-TOKEN");
并在我的 Chrome 工具中确认正在设置 cookie。如果我省略上面的行,cookie 仍然设置为部分随机名称,例如: .AspNetCore.Antiforgery.RAtR0X9F8_w
无论哪种方式设置 cookie。我还确认,每当我重新启动整个应用程序时,cookie 值都会更新,因此框架会主动设置此 cookie。
在我的 Chrome 工具中观察网络请求,我确认 cookie 是根据 AJAX 请求发送到服务器的。在服务器上放置断点并观察控制器操作中的 Request.Cookies
值也证实了这一点。
但是,如果我用 [ValidateAntiForgeryToken]
修饰任何此类 AJAX 请求的操作,则响应始终为空 400。
我是否遗漏了某个配置步骤?也许 action 属性在错误的地方查找,我需要使用不同的验证?
我刚刚查看了日志,发现有一个异常:
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery cookie ".AspNetCore.Antiforgery.HPE6W9qucDc" is not present.
at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)
表示你forgot to configure the cookie name :
public void ConfigureServices(IServiceCollection services)
{
//services.AddAntiforgery();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
所以我只添加如下配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(o => {
o.Cookie.Name = "X-CSRF-TOKEN";
});
// ...
}
现在可以使用了。
此外,如果您想省略 services.AddAntiforgery(options => options.Cookie.Name = "X-CSRF-TOKEN");
这一行,您可以使用内置的 antiforgery.GetAndStoreTokens(context)
方法发送 cookie:
app.Use(next => context =>
{
if (context.Request.Path == "/")
{
//var tokens = antiforgery.GetTokens(context);
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("X-CSRF-TOKEN", tokens.CookieToken, new CookieOptions { HttpOnly = false });
context.Response.Cookies.Append("X-CSRF-FORM-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
}
return next(context);
})
两者都应该按预期工作。
我正在尝试使用框架的工具向 ASP.NET Core React SPA 添加一些简单的 CSRF 验证。该应用程序本身本质上是一个 create-react-app 设置(带有根元素的单个 index.html,其他所有内容都从捆绑的 JavaScript 中加载)。
修改在 this one 等链接上找到的一些信息,我在 Startup.ConfigureServices
中设置了以下内容:
services.AddAntiforgery(options => options.Cookie.Name = "X-CSRF-TOKEN");
并在我的 Chrome 工具中确认正在设置 cookie。如果我省略上面的行,cookie 仍然设置为部分随机名称,例如: .AspNetCore.Antiforgery.RAtR0X9F8_w
无论哪种方式设置 cookie。我还确认,每当我重新启动整个应用程序时,cookie 值都会更新,因此框架会主动设置此 cookie。
在我的 Chrome 工具中观察网络请求,我确认 cookie 是根据 AJAX 请求发送到服务器的。在服务器上放置断点并观察控制器操作中的 Request.Cookies
值也证实了这一点。
但是,如果我用 [ValidateAntiForgeryToken]
修饰任何此类 AJAX 请求的操作,则响应始终为空 400。
我是否遗漏了某个配置步骤?也许 action 属性在错误的地方查找,我需要使用不同的验证?
我刚刚查看了日志,发现有一个异常:
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery cookie ".AspNetCore.Antiforgery.HPE6W9qucDc" is not present. at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext) at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)
表示你forgot to configure the cookie name :
public void ConfigureServices(IServiceCollection services) { //services.AddAntiforgery(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); // In production, the React files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/build"; }); }
所以我只添加如下配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(o => {
o.Cookie.Name = "X-CSRF-TOKEN";
});
// ...
}
现在可以使用了。
此外,如果您想省略 services.AddAntiforgery(options => options.Cookie.Name = "X-CSRF-TOKEN");
这一行,您可以使用内置的 antiforgery.GetAndStoreTokens(context)
方法发送 cookie:
app.Use(next => context =>
{
if (context.Request.Path == "/")
{
//var tokens = antiforgery.GetTokens(context);
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("X-CSRF-TOKEN", tokens.CookieToken, new CookieOptions { HttpOnly = false });
context.Response.Cookies.Append("X-CSRF-FORM-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
}
return next(context);
})
两者都应该按预期工作。