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

Angular中xsrfTokenExtractor.getToken()返回null的.NET7 WebAPI CSRF问题

.NET 7 WebAPI + Angular XSRF验证失败问题分析与解决

问题背景

API已返回XSRF-TOKEN Cookie,但Angular的XSRF拦截器中xsrfTokenExtractor.getToken()始终返回null,导致请求未携带X-XSRF-TOKEN头,被带[ValidateAntiForgeryToken]特性的接口返回400 Bad Request错误。API部署在https://localhost:7129,Angular运行在http://127.0.0.1:4210,跨域场景下出现该问题。

核心原因分析

1. 跨域同源策略限制

localhost和127.0.0.1被浏览器视为不同源,加上响应头中Set-Cookie包含SameSite=Strict属性,浏览器会阻止跨域请求携带该Cookie,导致Angular无法读取到XSRF-TOKEN。同时存在两个Set-Cookie条目,其中一个带HttpOnly属性,前端完全无法读取,进一步混淆了Cookie的有效性。

2. CORS配置错误

当前CORS策略使用AllowAnyOrigin(),但当请求需要携带凭证(如Cookie)时,浏览器不允许Access-Control-Allow-Origin设为*,会直接阻止凭证发送,导致Cookie无法被Angular读取。

3. Angular拦截器配置缺陷

拦截器仅在拿到token时才设置withCredentials: true,但实际上如果没有先携带凭证发送请求,浏览器根本不会返回Cookie,导致getToken()永远拿不到值,形成恶性循环。

4. 后端Cookie重复设置

代码中手动调用context.Response.Cookies.Append("XSRF-TOKEN", ...),同时Antiforgery中间件自动生成了另一个带HttpOnly的Cookie,造成响应头中Cookie重复,无效Cookie干扰了有效Cookie的读取。

解决方案

后端(.NET 7)调整

修改CORS策略

指定具体前端源并允许携带凭证:

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyCors",
                      builder =>
                      {
                          builder.WithOrigins("http://127.0.0.1:4210", "http://localhost:4210")
                                 .AllowAnyMethod()
                                 .AllowAnyHeader()
                                 .AllowCredentials();
                      });
});

修正Antiforgery配置

统一Cookie规则,避免重复设置:

builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "X-XSRF-TOKEN";
    options.Cookie.Name = "XSRF-TOKEN";
    options.Cookie.SameSite = SameSiteMode.Lax; // 跨域场景可设为SameSiteMode.None(需配合HTTPS)
    options.Cookie.HttpOnly = false;
});

移除手动设置Cookie的代码

删除app.Use(...)中手动Append Cookie的逻辑,Antiforgery中间件会自动处理Token的生成与Cookie设置。

前端(Angular)调整

修改XSRF拦截器

确保所有请求都携带凭证:

@Injectable()
export class XsrfInterceptor implements HttpInterceptor {
  constructor(private xsrfTokenExtractor: HttpXsrfTokenExtractor) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // 先克隆请求并开启凭证携带
    const baseRequest = req.clone({ withCredentials: true });
    
    const xsrfToken = this.xsrfTokenExtractor.getToken();
    if (xsrfToken) {
      return next.handle(baseRequest.clone({
        headers: baseRequest.headers.set('X-XSRF-TOKEN', xsrfToken)
      }));
    }
    
    return next.handle(baseRequest);
  }
} 

关键结论

前后端域名(localhost与127.0.0.1)不一致确实是导致问题的核心因素之一,结合CORS配置错误、Cookie属性不匹配、拦截器逻辑缺陷,最终造成XSRF Token无法被正确读取和携带。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:05:56