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

Blazor WASM JWT - How to get auth state in MainLayout

$
0
0

I wanted to set up authentication in Blazor WebAssembly, JWT, Net 8, but I encountered a problem. When I place tags in an interactive component, like here:

@page "/"@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))@inject IStringLocalizer<Login> Localizer@using Microsoft.AspNetCore.Components.Authorization<CascadingAuthenticationState><AuthorizeView><Authorized>            Authorized</Authorized><NotAuthorized>            NotAuthorized</NotAuthorized></AuthorizeView></CascadingAuthenticationState>

My AuthenticationStateProvider works fine and returns Authorized or NotAuthorized. But when I try to do it in MainLayout.razor, like here:

@using Microsoft.AspNetCore.Components.Authorization@inherits LayoutComponentBase<CascadingAuthenticationState><AuthorizeView><Authorized>            Authorized</Authorized><NotAuthorized>            NotAuthorized</NotAuthorized></AuthorizeView></CascadingAuthenticationState>

I always get NotAuthorized. This happens because the application is not rendered interactively in MainLayout.razor. How can I fix this?

My JwtAuthenticationStateProvider.cs:

using Blazored.LocalStorage;using Microsoft.AspNetCore.Components.Authorization;using Microsoft.JSInterop;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;namespace WMS.Client.Providers;public class JwtAuthenticationStateProvider(ILocalStorageService LocalStorage, IJSRuntime JSRuntime) : AuthenticationStateProvider{    private readonly ILocalStorageService _localStorage = LocalStorage;    private readonly IJSRuntime _JSRuntime = JSRuntime;    private const string TokenKey = "authToken";    public sealed override async Task<AuthenticationState> GetAuthenticationStateAsync()    {        if (_JSRuntime is not IJSInProcessRuntime)            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));        var token = await _localStorage.GetItemAsync<string>(TokenKey);        if (string.IsNullOrEmpty(token))            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));        var user = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));        return new AuthenticationState(user);    }    public async Task Login(string token)    {        await _localStorage.SetItemAsync(TokenKey, token);        var user = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));    }    public async Task Logout()    {        await _localStorage.RemoveItemAsync(TokenKey);        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()))));    }    private static IEnumerable<Claim> ParseClaimsFromJwt(string token)    {        var handler = new JwtSecurityTokenHandler();        var jwt = handler.ReadJwtToken(token);        return jwt.Claims;    }}

My Routes.razor:

@using Microsoft.AspNetCore.Components.Authorization<CascadingAuthenticationState><Router AppAssembly="@typeof(App).Assembly"><Found Context="routeData"><AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" /></Found><NotFound><LayoutView Layout="@typeof(Layout.MainLayout)"><p>Sorry, there's nothing at this address.</p></LayoutView></NotFound></Router></CascadingAuthenticationState>

App.razor:

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><base href="/" /><link href="app.css" rel="stylesheet" /><link href="WMS.styles.css" rel="stylesheet" /><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><HeadOutlet /><script src="js/site.js"></script></head><body><Routes /><script src="_framework/blazor.web.js"></script></body></html>

Program.cs in client side:

using Blazored.LocalStorage;using Microsoft.AspNetCore.Components.Authorization;using Microsoft.AspNetCore.Components.WebAssembly.Hosting;using System.Globalization;using WMS.Client.Providers;var builder = WebAssemblyHostBuilder.CreateDefault(args);builder.Services.AddBlazoredLocalStorage();builder.Services.AddLocalization(options => { options.ResourcesPath = "Resources"; });builder.Services.AddAuthorizationCore();builder.Services.AddScoped<JwtAuthenticationStateProvider>();builder.Services.AddScoped<AuthenticationStateProvider, JwtAuthenticationStateProvider>();CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");await builder.Build().RunAsync();

Program.cs in server side:

using Blazored.LocalStorage;using Microsoft.AspNetCore.Components.Authorization;using WMS.Client.Providers;using WMS.Components;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddRazorComponents()    .AddInteractiveWebAssemblyComponents();builder.Services.AddBlazoredLocalStorage();builder.Services.AddAuthorization();builder.Services.AddScoped<JwtAuthenticationStateProvider>();builder.Services.AddScoped<AuthenticationStateProvider, JwtAuthenticationStateProvider>();var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){    app.UseWebAssemblyDebugging();}else{    app.UseExceptionHandler("/Error", createScopeForErrors: true);}app.UseStaticFiles();app.UseAntiforgery();app.MapRazorComponents<App>()    .AddInteractiveWebAssemblyRenderMode()    .AddAdditionalAssemblies(typeof(WMS.Client._Imports).Assembly);app.Run();

Viewing all articles
Browse latest Browse all 4839

Trending Articles



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