Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4837

Use authentication with cookies instead of losing login on page refresh

$
0
0

I am working on an internal tool (MudBlazor, C# .NET 8) 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.Issue from my previous question:

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.

This issue was resolved by changing the render mode in App.razor:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender:false)" /><Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Additionally, I no longer use JSInterop via a global using statement (in _Imports.razor), but only on a different page (not the one causing the issue).

This solution also resolved the issue:

public class BlazorAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler    {        public Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)        {            return next(context);        }    } 

Now, I need to ensure that when manually entering a URL in the browser's address bar, the user remains logged in. Currently, there is no error message, but I get logged out when I refresh or enter a new URL. After debugging, I found that I was suddenly logged out, even though I had previously logged in.

I was told to use authentication by using cookies, but I haven't been able to get it working so far. I am not using JWT.

I am no longer using @attribute [Authorize] on pages, because otherwise, nothing (for example, MudText) gets displayed — not even a message like "Please log in first." Instead, I simply check in the code if the user is logged in and return early if they are not.

Could you help me implement this?

Program.cs

using Microsoft.AspNetCore.Components.Authorization;using MudBlazor.Services;var builder = WebApplication.CreateBuilder(args);// Add MudBlazor servicesbuilder.Services.AddMudServices();// Add services to the container.builder.Services.AddRazorComponents()    .AddInteractiveServerComponents();builder.Services.AddSingleton<InitializationStateService>(); // Logging accesses to json filebuilder.Services.AddScoped<CustomAuthStateProvider>();builder.Services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<CustomAuthStateProvider>());builder.Services.AddAuthorizationCore();builder.Services.AddSingleton<Microsoft.AspNetCore.Authorization.IAuthorizationMiddlewareResultHandler, BlazorAuthorizationMiddlewareResultHandler>();builder.Services.AddAuthentication(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme)    .AddCookie(options =>    {        options.Cookie.Name = "auth_token";        options.Cookie.MaxAge = TimeSpan.FromMinutes(30);        options.LoginPath = "/login";        options.LogoutPath = "/logout";        options.ExpireTimeSpan = TimeSpan.FromHours(1);        options.SlidingExpiration = true;    });builder.Services.AddAuthorization();builder.Services.AddCascadingAuthenticationState();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.UseAuthentication();app.UseAuthorization();app.UseHealthChecks("/health");app.MapRazorComponents<App>()    .AddInteractiveServerRenderMode();app.Run();

CustomAuthStateProvider.cs

    using Microsoft.AspNetCore.Authentication.Cookies;    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)            }, CookieAuthenticationDefaults.AuthenticationScheme);            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;        }    }

BlazorAuthorizationMiddlewareResultHandler.cs

public class BlazorAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler{    public Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)    {        return next(context);    }}

Routes.razor

<Microsoft.AspNetCore.Components.Authorization.AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />

Viewing all articles
Browse latest Browse all 4837

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>