Reputation: 133
I have an app built using .NET8 Blazor with InteractiveServerRenderMode.
App.razor is configured like in Template you get when you create Blazor Server App with Global Interactivity and Identity.
I have one Toolbar component where I am trying to add SignOut Functionality with following form
<AuthorizeView>
<Authorized>
<form action="Account/Logout" method="post">
<AntiforgeryToken />
<input type="hidden" name="ReturnUrl" value="@currentUrl" />
<button type="submit">Sign out</button>
</form>
</Authorized>
</AuthorizeView>
But when I submit this form with Sign out button I get following error
BadHttpRequestException: Invalid anti-forgery token found when reading parameter "string returnUrl" from the request body as form.
This error is right as when I inspect element I don't see __RequestVerificationToken field. It is not beind rendered I even tried to use @attribute [RequireAntiforgeryToken]
but it is still not working.
I also tried to register it in Program.cs as
var app = builder.Build();
if (app.Environment.IsDevelopment())
app.UseMigrationsEndPoint();
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
//app.UseAuthentication();
//app.UseAuthorization();
app.UseAntiforgery();
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
app.MapAdditionalIdentityEndpoints();
app.Run();
Anyone who can point what I am doing wrong here?
Upvotes: 10
Views: 1937
Reputation: 29
you can add an input hidden field, and in the code, get the token, try this solution in blazor server side app
builder.Services.AddAntiforgery(options =>
{
options.HeaderName = "RequestVerificationToken"; // Nom de l'en-tête à utiliser
});
app.UseAntiforgery(); // this line goes after app.UseAuthentication and app.UseAuthorization
@using System.Net.Http
@using Microsoft.AspNetCore.Antiforgery
@inject NavigationManager Navigation
@inject IHttpContextAccessor _httpContextAccessor;
<Authorized>
<form action="authentication/logout" method="post">
<input type="hidden" name="__RequestVerificationToken" value="@GetTokenAntiforgery()" /> @* this line *@
<div class="nav-item px-3 ctn__submit">
<img src="/img/box-arrow-right.svg" class="bi bi-box-arrow-right icon__submit" />
<button class="btn__submit nav-link" type="submit">
Se Déconnecter @* @context.User.Identity?.Name *@
</button>
</div>
</form>
</Authorized>
@code {
public string GetTokenAntiforgery()
{
var httpContext = _httpContextAccessor.HttpContext;
var tokens = _antiforgery.GetAndStoreTokens(httpContext ?? throw new InvalidOperationException("HttpContext is not available."));
if (string.IsNullOrEmpty(tokens.RequestToken))
{
throw new InvalidOperationException("RequestToken is not available");
}
return tokens.RequestToken;
}
}
Upvotes: 0
Reputation: 87
Replace <AntiforgeryToken />
with <input type="hidden" name="__RequestVerificationToken" value="@GetAntiforgeryToken()" />
and write the following method:
public string GetAntiforgeryToken()
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null)
{
throw new InvalidOperationException("HttpContext is not available.");
}
var tokens = _antiforgery.GetAndStoreTokens(httpContext);
return tokens.RequestToken;
}
Make sure you inject IAntiforgery and IHttpContextAccessor into your class, usually in the constructor:
private readonly IAntiforgery _antiforgery;
private readonly IHttpContextAccessor _httpContextAccessor;
public YourClass(IAntiforgery antiforgery, IHttpContextAccessor httpContextAccessor)
{
_antiforgery = antiforgery;
_httpContextAccessor = httpContextAccessor;
}
Upvotes: 2
Reputation: 11
Do you have the Server Side Blazor Service enabled in your app? I ran into the same exception when logging out a user, after builder.Services.AddServerSideBlazor();
was added to Program.cs. This caused both <EditForm ...>
and <AntiforgeryToken />
not creating a hidden input field with such antiforgery token on the forms, causing this exception when processing a form.
Solution thus was to remove builder.Services.AddServerSideBlazor();
from Program.cs.
I think it has to do with having Interactive/Client Side mode and Server Side mode simultaneously included in the Blazor app. Server Side does not need such tokens if I understand the documentation correctly, as the app runs on the server completely and validation is happening per connection. While the interactive mode is validating sessions instead, thus requiring the tokens.
Upvotes: 0
Reputation: 21
Not sure what exactly is happening here, but here's how i encountered this problem and how i "fixed" it.
I've been adapting the the Blazor WebApp template's code to my layout, that layout is built using MudBlazor
(version 6.20).
I've put Logout
div
inside the MudMenu
component with an ActivationEvent
, which would activate this menu dynamically on MouseOver
.
Here's sample code:
<MudMenu AnchorOrigin="Origin.BottomRight" ActivationEvent="@MouseEvent.MouseOver">
<ActivatorContent>
...
</ActivatorContent>
<ChildContent>
<AuthorizeView>
<Authorized>
...
<div class="nav-item px-3">
<form action="Account/Logout" method="post">
<AntiforgeryToken />
<input type="hidden" name="ReturnUrl" value="@currentUrl" />
<button type="submit" class="nav-link">
<span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true"></span> Logout
</button>
</form>
</div>
...
</Authorized>
</AuthorizeView>
</ChildContent>
</MudMenu>
And that caused the problem for me, the __RequestVerificationToken
field wasn't being generated in the form's HTML.
So I've ditched the MudMenu
in favor of simple buttons:
<MudStack Row="true">
<AuthorizeView>
<Authorized>
<MudNavLink Href="Account/Manage">
...
</MudNavLink>
<div class="nav-item px-3">
<form action="Account/Logout" method="post">
<AntiforgeryToken />
<input type="hidden" name="ReturnUrl" value="@currentUrl" />
<button type="submit" class="nav-link">
<span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true"></span> Logout
</button>
</form>
</div>
</Authorized>
</AuthorizeView>
</MudStack>
And now it works. So i guess there's was something interfering with the <AntiforgeryToken />
component. Hoppe this will help someone to identify what is causing this for them.
Upvotes: 2
Reputation: 25
In my case, I had to add one line to the IdentityComponentsEndpointRouteBuilderExtensions.cs file...
var accountGroup = endpoints.MapGroup("/Account");
accountGroup.DisableAntiforgery();
Upvotes: 0
Reputation: 28267
BadHttpRequestException: Invalid anti-forgery token found when reading parameter "string returnUrl" from the request body as form.
According to the error message, you should make sure you have put the app.UseAntiforgery();
middleware with the right order inside the program.cs.
Please note, according to this github issue, you need also put app.UseAntiforgery()
after app.UseAuthentication()
middleware to avoid this kind of issue.
More details, you could refer to below codes:
...
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();
app.Run();
Result:
Upvotes: 4