为什么 AntiForgeryToken 验证总是失败?

Why AntiForgeryToken validation keeps failing?

我正在使用 asp.net core2Angular 开发网络 API 应用 运行。详细的开发环境配置是here。 我正在尝试配置 AntiForgeryToken 验证,但它一直失败。我按照配置。 here,但我不得不修改它,因为我的 angular 应用程序和 asp.net 服务器在两个不同的端口上 运行,因为前端启动不会生成令牌。我通过在应用程序组件 ngOnInit 上调用 API 路径 (/api/Account/ContactInitialization) 来启动后端,这使我能够生成令牌。 配置如下所示,

IServiceCollection 服务:

        services.AddAntiforgery(options =>
                {
                    options.HeaderName = "X-CSRF-TOKEN";
                    options.SuppressXFrameOptionsHeader = false;
                });

IApplicationBuilder Configure:

app.Use(next => context =>
                {
                    string path = context.Request.Path.Value;
                    if (

                        string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(path, "/api/Account/ContactInitialization", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
                    {
                        // We can send the request token as a JavaScript-readable cookie, 
                        // and Angular will use it by default.
                         var tokens = antiforgery.GetAndStoreTokens(context);
                        context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                            new CookieOptions() { HttpOnly = false });
                    }

                    return next(context);
                });

asp.net。生成两组密钥,

我用 [ValidateAntiForgeryToken] 修饰了我的方法,并在我的 header 请求中包含了 XSRF-TOKEN cookie 内容。但是我在调​​用 API 之后一直收到 400 (Bad Request) 响应!我在这里错过了什么?

控制器方法,

    [Authorize]
    [ValidateAntiForgeryToken]
    [HttpPost]
    public IEnumerable<string> AutherizeCookie()
    {
        return new string[] { "Hello", "Auth Cookie" };
    }

我的详细 [​​=51=] 请求如下所示,

我假设您可能遵循了 documentation,但忽略了相关部分。到目前为止,您所做的仅适用于 Angular,因为 Angular 的 $http 实际上会在 [=13= 的基础上添加 X-XSRF-TOKEN header ] 曲奇饼。 (但是请注意,即便如此,您已经将 header 设置为 X-CSRF-TOKEN,这在这里实际上不起作用。它需要是 X-XSRF-TOKEN)。

但是,如果您不使用 Angular,则您有责任在 AJAX 请求中自行设置 header,而您可能忽略了这一点。在这种情况下,您实际上不需要更改任何防伪令牌配置(header 名称、设置 cookie 等)。您只需提供 header 作为 RequestVerificationToken。例如,jQuery:

$.ajax({
    ...
    headers:
    {
        "RequestVerificationToken": '@GetAntiXsrfRequestToken()'
    },
    ...
});

这将适用于 JavaScript 的视图。如果您需要在外部 JS 中执行此操作,则需要设置 cookie,以便您可以从 cookie 中获取值。除此之外,同样的方法适用。

如果您只是想更改 header 名称,您可以这样做;您只需要将此处的 RequestVerificationHeader 部分更改为相同的值即可。

谢谢@Chris_Pratt 指出我遇到的 header 问题。但是,为了清楚起见,我还有其他问题将在下面解决。

我的 CORS 配置错误,我的工作代码如下,

services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder
                        .WithOrigins("https://www.artngcore.com:4200") //Note:  The URL must be specified without a trailing slash (/).
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials());
            });

            services.AddAntiforgery(options =>
                {
                    options.HeaderName = "X-XSRF-TOKEN";
                    options.SuppressXFrameOptionsHeader = false;
                });  

并且 middleware 配置是,

app.Use(next => context =>
               {
                   string path = context.Request.Path.Value;
                   var tokens = antiforgery.GetAndStoreTokens(context);
                   context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                        new CookieOptions() { HttpOnly = false, 
Secure = true // set false if not using SSL });
                   return next(context);
               });

在控制器中,

[Route("/api/[controller]/[action]")]
[EnableCors("CorsPolicy")]
public class AccountController : ArtCoreSecuredController ....

这里的诀窍是令牌必须在身份验证后刷新。在身份验证(登录)之后调用 API 即可。 不要忘记在您的请求中添加以下 header,

 const headers = new HttpHeaders({
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${this.cookieService.get('ArtCoreToken')}`,
            'X-XSRF-TOKEN': `${this.cookieService.get('XSRF-TOKEN')}`
        });

    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> RefreshToken()
    {
        await Task.Delay(1);

        return StatusCode(200);

    } 

这对我有用。希望对你有帮助。

您需要使用 Credentials=true 发出 XHR 请求,这将使浏览器设置 cookie,否则您将收到 400 错误请求,因为 cookie 不存在并且 X-XSRF-TOKEN 未设置或已设置清空字符串