Blazor Server中<AntiforgeryToken/>无效导致防伪验证失败的解决方法
在Blazor Interactive Server组件中编写了提交到Microsoft Identity Core Logout端点的表单,已配置防伪中间件,但点击注销时触发AntiforgeryValidationException,提示缺少__RequestVerificationToken表单字段或RequestVerificationToken请求头。
组件代码
<form action="Account/Logout" method="post"> <AntiforgeryToken /> <input type="hidden" name="ReturnUrl" value="@currentUrl"> <button type="submit" class="nav-link border-0 text-white" @onclick="@Logout"> <LocalText Key="Logout"></LocalText> </button> </form>
端点代码
accountGroup.MapPost("/Logout", async ( ClaimsPrincipal user, SignInManager<AppUser> signInManager, [FromForm] string returnUrl) => { await signInManager.SignOutAsync(); return TypedResults.LocalRedirect($"~/{returnUrl}"); });
中间件配置
var app = builder.Build(); ... app.UseHttpsRedirection(); app.UseStaticFiles(); app.MapControllers(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseAntiforgery(); app.MapRazorPages(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode(); app.MapAdditionalIdentityEndpoints(); app.Run();
错误信息
处理请求时发生未处理的异常。
AntiforgeryValidationException: 未在表单字段“__RequestVerificationToken”或请求头“RequestVerificationToken”中提供所需的防伪请求令牌。
Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)BadHttpRequestException: 从请求正文中以表单形式读取参数“string returnUrl”时发现无效的防伪令牌。
Microsoft.AspNetCore.Http.RequestDelegateFactory+Log.InvalidAntiforgeryToken(HttpContext httpContext, string parameterTypeName, string parameterName, Exception exception, bool shouldThrow)堆栈跟踪:
AntiforgeryValidationException: 未在表单字段“__RequestVerificationToken”或请求头“RequestVerificationToken”中提供所需的防伪请求令牌。
Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgeryMiddleware.InvokeAwaited(HttpContext context)
1. 移除按钮的@onclick事件绑定
Blazor Interactive Server中,给表单提交按钮添加@onclick会优先触发Blazor客户端交互逻辑,而非直接提交表单,导致AntiforgeryToken无法正确携带到请求中。直接移除该绑定:
<form action="Account/Logout" method="post"> <AntiforgeryToken /> <input type="hidden" name="ReturnUrl" value="@currentUrl"> <button type="submit" class="nav-link border-0 text-white"> <LocalText Key="Logout"></LocalText> </button> </form>
2. 验证AntiforgeryToken是否正确渲染
查看页面源代码,确认<AntiforgeryToken />是否生成了名称为__RequestVerificationToken的隐藏输入字段。如果未生成,可手动添加:
<input type="hidden" name="__RequestVerificationToken" value="@Antiforgery.GetAndStoreTokens(HttpContextAccessor.HttpContext).RequestToken" />
需在组件中注入相关服务:
@inject IAntiforgery Antiforgery @inject IHttpContextAccessor HttpContextAccessor
3. 显式给端点添加防伪验证
虽然UseAntiforgery()中间件会自动验证POST请求,但显式给端点添加验证可确保逻辑生效:
accountGroup.MapPost("/Logout", async ( ClaimsPrincipal user, SignInManager<AppUser> signInManager, [FromForm] string returnUrl) => { await signInManager.SignOutAsync(); return TypedResults.LocalRedirect($"~/{returnUrl}"); }).RequireAntiforgery();
内容的提问来源于stack exchange,提问作者mz1378

