ASP.NET Core WebAPI CSRF验证失败:未识别自定义请求头令牌
解决ASP.NET Core WebAPI CSRF验证不通过问题
登录认证后,后端将CSRF令牌存入XSRF-TOKEN Cookie,前端获取后在后续请求头中添加X-XSRF-TOKEN,但验证始终失败,系统持续检查.AspNetCore.Antiforgery.xxx Cookie,而非传入的请求头令牌。
后端中间件代码
public class CsrfValidationMiddleware { private readonly IAntiforgery _antiforgery; private readonly RequestDelegate _next; public CsrfValidationMiddleware(RequestDelegate next, IAntiforgery antiforgery) { _next = next ?? throw new ArgumentNullException(nameof(next)); _antiforgery = antiforgery ?? throw new ArgumentNullException(nameof(antiforgery)); } public async Task InvokeAsync(HttpContext context) { var isGetRequest = string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase); if (context.Request.Path == "/v1/api/login") { // Obtain and store anti-forgery tokens, including setting the cookie var antiforgeryTokens = _antiforgery.GetAndStoreTokens(context); // Access the CSRF token var csrfToken = antiforgeryTokens.RequestToken; // Add CSRF token to response headers context.Response.Cookies.Append("XSRF-TOKEN", csrfToken, new CookieOptions { HttpOnly = false, SameSite = SameSiteMode.None, // Adjust based on your requirements Secure = true // If your site is served over HTTPS }); } // Validate anti-forgery token for non-GET requests if (!isGetRequest && context.Request.Path != "/v1/api/login") { await _antiforgery.ValidateRequestAsync(context); } // Call the next middleware in the pipeline await _next(context); } }
React TypeScript请求代码
static api() { const jwtToken = localStorage.getItem('token') let token = Cookies.get("XSRF-TOKEN"); console.log('maq',token) return axios.create({ baseURL: process.env.BaseASE_URL, headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json', Authorization: 'Bearer ' + jwtToken, 'X-XSRF-TOKEN':localStorage.getItem('csrf') } }) }
问题原因及解决方案
1. 核心原因
ASP.NET Core Antiforgery默认使用自有命名的Cookie(.AspNetCore.Antiforgery.xxx)和请求头(RequestVerificationToken),你的代码中手动设置了XSRF-TOKEN Cookie,但Antiforgery并未被配置为使用这些自定义名称,导致验证时仍在查找默认Cookie。
2. 具体修复步骤
(1)配置Antiforgery自定义名称
在Program.cs(或Startup.cs)中添加Antiforgery配置,指定要使用的Cookie和请求头名称:
builder.Services.AddAntiforgery(options => { // 指定Cookie名称为XSRF-TOKEN options.Cookie.Name = "XSRF-TOKEN"; // 指定请求头名称为X-XSRF-TOKEN options.HeaderName = "X-XSRF-TOKEN"; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.SameSite = SameSiteMode.None; options.Cookie.HttpOnly = false; });
(2)简化中间件逻辑
GetAndStoreTokens方法会根据上述配置自动设置XSRF-TOKEN Cookie,无需手动调用Append,避免重复设置:
if (context.Request.Path == "/v1/api/login") { var antiforgeryTokens = _antiforgery.GetAndStoreTokens(context); // 可选:将令牌添加到响应头,方便前端直接获取 context.Response.Headers.Append("X-CSRF-TOKEN", antiforgeryTokens.RequestToken); }
(3)修复前端请求代码
- 直接从Cookie读取
XSRF-TOKEN,而非从localStorage取未存储的csrf值 - 开启
withCredentials: true,确保浏览器携带Cookie到后端 - 移除不必要的
Access-Control-Allow-Origin请求头(这是后端响应头字段)
static api() { const jwtToken = localStorage.getItem('token'); const xsrfToken = Cookies.get("XSRF-TOKEN"); return axios.create({ baseURL: process.env.BaseASE_URL, headers: { 'Content-Type': 'application/json', Authorization: jwtToken ? `Bearer ${jwtToken}` : '', 'X-XSRF-TOKEN': xsrfToken || '' }, withCredentials: true // 必须开启,否则浏览器不发送Cookie }); }
(4)跨域环境补充配置
如果前后端存在跨域,需在后端Cors配置中允许携带凭证:
builder.Services.AddCors(options => { options.AddPolicy("AllowFrontend", policy => { policy.WithOrigins("你的前端域名") // 替换为实际前端域名 .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); // 必须允许凭证传递 }); }); // 在中间件管道中启用Cors(需放在UseRouting之后,UseAuthorization之前) app.UseCors("AllowFrontend");
内容的提问来源于stack exchange,提问作者Maq Na
相关产品推荐
相关产品推荐

