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

非MVC项目中React集成Antiforgery致POST请求400错误排查

ASP.NET Core + React 跨域防伪造Token验证400错误修复方案

问题根源

  • 服务端在需要验证的POST/PUT/DELETE请求中重复调用GetAndStoreTokens,每次都会生成新Token,导致请求携带的旧Token与服务端当前存储的Token不匹配,验证失败。
  • Cookie的SameSite=Strict配置在跨域场景下(不同端口属于跨域)会阻止浏览器发送Cookie,服务端无法拿到存储的Token进行验证。
  • 客户端错误地在请求头中设置了Access-Control-Allow-Credentials,该字段仅需服务端在响应头中返回,客户端设置无效且可能引发冲突。

修复步骤

服务端调整

  1. 限制Token生成时机:仅在GET请求(如首页、专门的Token接口)中生成并返回Anti-Forgery Token,避免在需要验证的请求中生成新Token覆盖旧值。
  2. 修正Cookie SameSite配置:将SameSiteMode.Strict改为SameSiteMode.Lax(本地HTTP环境)或SameSiteMode.None(HTTPS环境,需配合Secure=true),确保跨域场景下Cookie能正常发送。
  3. 简化Token存储逻辑:GetAndStoreTokens会自动处理Cookie的设置,无需手动调用context.Response.Cookies.Append,避免重复写入Cookie导致多个Token值。
  4. 完善CORS配置:确保CORS策略允许携带凭据(.AllowCredentials()),并正确暴露必要的响应头。

客户端调整

  1. 移除无效请求头:删除请求头中的Access-Control-Allow-Credentials字段。
  2. 确保Token获取时机:先发送GET请求获取Token,待Cookie写入后再携带Token发送POST/PUT/DELETE请求。

修正后代码示例

服务端Startup.cs代码

// 配置Anti-Forgery服务
services.AddAntiforgery(options =>
{
    options.HeaderName = "X-XSRF-TOKEN";
    options.Cookie.Name = "XSRF-TOKEN";
    options.Cookie.SameSite = SameSiteMode.Lax; // 跨域场景改为Lax或None
    options.Cookie.HttpOnly = false;
    options.Cookie.Secure = false; // 本地HTTP环境设为false,HTTPS环境改为true
});

// 配置CORS
services.AddCors(options =>
{
    options.AddPolicy("ReactCors", policy =>
    {
        policy.WithOrigins("http://localhost:1000")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials() // 必须允许凭据
              .WithExposedHeaders("X-XSRF-TOKEN");
    });
});

// 中间件调整:仅在GET请求生成Token
app.Use(async (context, next) =>
{
    var antiforgery = context.RequestServices.GetRequiredService<IAntiforgery>();
    
    // 仅在GET请求时生成并存储Token
    if (HttpMethods.IsGet(context.Request.Method))
    {
        antiforgery.GetAndStoreTokens(context);
    }

    await next(context);
});

// 启用CORS(注意顺序:在UseRouting之后,UseAuthorization之前)
app.UseCors("ReactCors");

客户端React请求代码

// 获取Cookie的工具函数
function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
}

// 先获取Token再发送POST请求
async function sendPostRequest() {
    // 先发起GET请求获取Token(比如访问服务根路径)
    await fetch('http://localhost:2000/', {
        credentials: 'include'
    });

    // 准备POST请求头
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');
    headers.append('X-XSRF-TOKEN', getCookie('XSRF-TOKEN'));

    // 发送POST请求
    const response = await fetch('http://localhost:2000/api/your-endpoint', {
        method: 'POST',
        credentials: 'include',
        headers: headers,
        body: JSON.stringify({ /* 请求体数据 */ })
    });

    if (response.ok) {
        // 处理成功响应
    } else {
        // 处理错误
    }
}

补充说明

  • 本地开发环境无需HTTPS也能正常工作,只要Cookie的Secure设为false即可;生产环境建议启用HTTPS,并将Secure设为true,SameSite设为None。
  • 确保[ValidateAntiforgeryToken]特性仅应用于需要验证的POST/PUT/DELETE接口,GET接口无需添加。

内容的提问来源于stack exchange,提问作者Erik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:28:17