admin管理员组文章数量:1403352
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="+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.UseAntifery();
app.MapRazorComponents<App>()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(WMS.Client._Imports).Assembly);
app.Run();
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/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.UseAntifery();
app.MapRazorComponents<App>()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(WMS.Client._Imports).Assembly);
app.Run();
Share
Improve this question
edited Mar 25 at 5:51
Qiang Fu
9,3871 gold badge6 silver badges16 bronze badges
asked Mar 20 at 23:33
Mikołaj SzczepekMikołaj Szczepek
132 bronze badges
1 Answer
Reset to default 0You could set the page rendermode (include mainlayout) dynamically based on the route in App.razor
<HeadOutlet @rendermode="PageRenderMode()" />
...
<Routes @rendermode="PageRenderMode()" />
...
@code {
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? PageRenderMode()
{
//if route start with acount use your rendermode
if (HttpContext.Request.Path.StartsWithSegments("/Account"))
{
return new InteractiveWebAssemblyRenderMode(prerender: false);
}
return null;
}
}
本文标签: cBlazor WASM JWTHow to get auth state in MainLayoutStack Overflow
版权声明:本文标题:c# - Blazor WASM JWT - How to get auth state in MainLayout - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744378728a2603391.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论