You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core WebAPI防伪令牌验证失败问题排查求助

解决ASP.NET Core 2 WebAPI与Angular 5防伪令牌交换错误的问题

你遇到的"Validation of the provided antiforgery token failed. The cookie token and the request token were swapped"错误,核心原因是ASP.NET Core Antiforgery的令牌结构和Angular的默认防伪机制不匹配,导致客户端发送的令牌和服务器期望的位置搞反了。下面一步步帮你排查和解决:

1. 先理清两者的默认行为差异

  • Angular 5默认逻辑:自动读取名为XSRF-TOKEN的Cookie值,然后将其放到请求头X-XSRF-TOKEN中,随POST/PUT/DELETE请求发送。
  • ASP.NET Core Antiforgery默认逻辑:生成两个关联的令牌:
    • 一个存储在Cookie中的Cookie令牌(默认名称__RequestVerificationToken)
    • 一个需要随请求发送的请求令牌(可以是表单字段或请求头)
      服务器验证时,需要同时收到这两个令牌,且它们必须匹配。

你的配置错误在于直接将Antiforgery的Cookie名称设为XSRF-TOKEN,导致Angular把Cookie令牌当成请求令牌发送,服务器自然会判定两者交换了。

2. 修正Startup.cs的Antiforgery配置

首先修改ConfigureServices中的Antiforgery配置,调整为适配Angular的逻辑:

public void ConfigureServices(IServiceCollection services)
{
    // ...其他配置
    services.AddAntiforgery(options =>
    {
        // 保持Antiforgery的Cookie为默认名称(或自定义内部名称,不要用XSRF-TOKEN)
        // options.Cookie.Name = "__RequestVerificationToken"; // 可省略,默认值就是这个
        options.HeaderName = "X-XSRF-TOKEN"; // 告诉服务器从这个头读取请求令牌
        options.FormFieldName = "F-XSRF-TOKEN"; // 修正拼写错误(你之前写的是XSFR)
    });
    // ...其他配置
}

接下来需要在请求管道中添加一个中间件,负责生成Antiforgery的请求令牌,并将其写入XSRF-TOKEN Cookie,供Angular读取:

在Configure方法中,在app.UseMvc()之前添加:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
{
    // ...其他中间件(比如UseStaticFiles、UseAuthentication等)
    
    // 添加生成XSRF-TOKEN的中间件
    app.Use(async (context, next) =>
    {
        // 针对GET/HEAD/OPTIONS请求,生成并设置XSRF-TOKEN Cookie
        if (context.Request.Method == "GET" || context.Request.Method == "HEAD" || context.Request.Method == "OPTIONS")
        {
            // 获取请求令牌
            var tokens = antiforgery.GetAndStoreTokens(context);
            // 将请求令牌写入XSRF-TOKEN Cookie,设置SameSite和禁用HttpOnly(否则Angular无法读取)
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                new CookieOptions() { HttpOnly = false, SameSite = SameSiteMode.Strict });
        }
        await next();
    });

    app.UseMvc();
}

这里的关键细节:

  • 只对安全的GET类请求生成令牌(避免重复生成)
  • HttpOnly = false:必须禁用HttpOnly,否则Angular的JavaScript无法读取这个Cookie
  • SameSite = SameSiteMode.Strict:提升安全性,防止跨站请求

4. 给需要验证的API方法添加防伪验证

在你的POST/PUT/DELETE控制器方法上添加[ValidateAntiForgeryToken]特性:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create([FromBody] YourModel model)
{
    // ...你的业务逻辑
}

如果想让所有API都验证,可以在控制器上添加这个特性,或者配置全局过滤器。

5. 跨域场景额外配置(如果需要)

如果你的Angular应用和WebAPI不在同一域名下,需要在ASP.NET Core中配置CORS允许凭据:

services.AddCors(options =>
{
    options.AddPolicy("AllowAngularApp",
        builder => builder.WithOrigins("http://your-angular-domain.com")
                          .AllowAnyHeader()
                          .AllowAnyMethod()
                          .AllowCredentials());
});

然后在Configure中启用CORS:

app.UseCors("AllowAngularApp");

常见坑点排查

  • 拼写错误:你之前的FormFieldName写成了F-XSFR-TOKEN,正确应该是F-XSRF-TOKEN(虽然Angular用不到表单字段,但还是建议修正)
  • HttpOnly设置:如果XSRF-TOKEN Cookie的HttpOnly设为true,Angular无法读取,导致请求头没有令牌
  • 跨域时未启用AllowCredentials:CORS必须允许携带Cookie,否则Angular不会发送X-XSRF-TOKEN头

按照以上步骤配置后,应该就能解决令牌交换的错误了。

内容的提问来源于stack exchange,提问作者NCC-2909-M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:13:51