I am working on an internal tool that displays data from a database. The application uses authentication, managed by a CustomAuthStateProvider, which allows users to log in and out. Certain actions are restricted to authenticated users, and this functionality has been working correctly.
However, I encountered an issue when trying to navigate to a specific page. The navigation is triggered using the following line:NavigationManager.NavigateTo($"/myPage/dateFrom={System.Uri.EscapeUriString(fromStr)}/dateTo={System.Uri.EscapeUriString(toStr)}", forceLoad: true);
The important part here is forceLoad: true. The error only occurs when forceLoad: true is used. When this navigation occurs, the application crashes with the following error message:
InvalidOperationException: Unable to find the required 'IAuthenticationService' service.Please add all the required services by calling 'IServiceCollection.AddAuthentication' in the application startup code.
Additional Finding
If I manually enter some URL of the app into the browser's address bar and press Enter, the same error occurs.
Further attempts
I tried refactoring some parts of the authentication logic and then encountered a new error:
The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action configureOptions).
In response to this, I attempted to use the solution suggested in this StackOverflow answer, but it did not resolve the issue.
Next, I tried to follow the approach outlined in this answer, but I ran into additional errors during implementation.
CustomAuthStateProvider.cs
using Microsoft.AspNetCore.Components.Authorization; using System.Security.Claims; using System.Threading.Tasks; public class CustomAuthStateProvider : AuthenticationStateProvider { public CustomAuthStateProvider() { this.CurrentUser = this.GetAnonymous(); } private ClaimsPrincipal CurrentUser { get; set; } private ClaimsPrincipal GetUser(string userName, uint id, string role) { var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes. Sid, id.ToString(new System.Globalization.CultureInfo("de-DE"))), new Claim(ClaimTypes.Name, userName), new Claim(ClaimTypes.Role, role) }, "Authentication type"); return new ClaimsPrincipal(identity); } private ClaimsPrincipal GetAnonymous() { var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Sid, "0"), new Claim(ClaimTypes.Name, "Anonymous"), new Claim(ClaimTypes.Role, "Anonymous") }, null); return new ClaimsPrincipal(identity); } public override Task<AuthenticationState> GetAuthenticationStateAsync() { var task = Task.FromResult(new AuthenticationState(this.CurrentUser)); return task; } public Task<AuthenticationState> ChangeUser(string username, uint id, string role) { this.CurrentUser = this.GetUser(username, id, role); var task = this.GetAuthenticationStateAsync(); this.NotifyAuthenticationStateChanged(task); return task; } public Task<AuthenticationState> Logout() { this.CurrentUser = this.GetAnonymous(); var task = this.GetAuthenticationStateAsync(); this.NotifyAuthenticationStateChanged(task); return task; } }Program.cs
var builder = WebApplication.CreateBuilder(args);// Add MudBlazor servicesbuilder.Services.AddMudServices();// Add services to the container.builder.Services.AddRazorComponents() .AddInteractiveServerComponents();builder.Services.AddSingleton<InitializationStateService>(); // Loggingbuilder.Services.AddScoped<CustomAuthStateProvider>();builder.Services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<CustomAuthStateProvider>());builder.Services.AddAuthorizationCore();builder.Services.AddServerSideBlazor().AddCircuitOptions(options =>{ options.DetailedErrors = true; options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(0); options.DisconnectedCircuitMaxRetained = 0;});builder.Services.AddHealthChecks();var app = builder.Build();// Configure the HTTP request pipeline.if (!app.Environment.IsDevelopment()){ app.UseExceptionHandler("/Error", createScopeForErrors: true);}app.UseStaticFiles();app.UseAntiforgery();app.UseHealthChecks("/health");app.MapRazorComponents<App>() .AddInteractiveServerRenderMode();app.Run();