.NET 8 Blazor Server自定义JWT认证添加[Authorize]后返回401错误
在.NET 7等旧版本中运行正常的相似代码,迁移到.NET 8的Blazor Server项目后出现异常:当为页面添加@attribute [Authorize]特性时,会返回“HTTP ERROR 401”错误。
Program.cs 代码
using BlazorServerCustomAuthTest.Auth; using BlazorServerCustomAuthTest.Components; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.IdentityModel.Tokens; using System.Text; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.SaveToken = true; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidAudience = "XXXX", ValidIssuer = "XXXX", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("XXXX")) }; }); // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); builder.Services.AddScoped<AuthStateProvider>(); builder.Services.AddScoped<AuthenticationStateProvider, AuthStateProvider>( provider => provider.GetRequiredService<AuthStateProvider>() ); builder.Services.AddScoped<ILoginService, AuthStateProvider>( provider => provider.GetRequiredService<AuthStateProvider>() ); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseAntiforgery(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode(); app.Run();
Routes.razor 代码
<Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"> <NotAuthorized> <text>Custom not authorized...</text> </NotAuthorized> </AuthorizeRouteView> <FocusOnNavigate RouteData="routeData" Selector="h1" /> </Found> </Router>
AuthStateProvider.cs 代码
using Microsoft.AspNetCore.Components.Authorization; using System.Net.Http.Headers; using System.Security.Claims; using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; using BlazorServerCustomAuthTest.Models; namespace BlazorServerCustomAuthTest.Auth { public class AuthStateProvider : AuthenticationStateProvider, ILoginService { private ProtectedSessionStorage ProtectedSessionStore; static AuthenticationState Anonymous => new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); public AuthStateProvider(ProtectedSessionStorage ProtectedSessionStore) { this.ProtectedSessionStore = ProtectedSessionStore; } public async override Task<AuthenticationState> GetAuthenticationStateAsync() { UserProfile? user; var result = await ProtectedSessionStore.GetAsync<UserProfile>("UserProfile"); if (result.Success) { user = result.Value; return await Task.FromResult(BuildAuthenticationState(user)); } else { return Anonymous; } } public async Task Login(UserProfile user) { await ProtectedSessionStore.SetAsync("UserProfile", user); var authState = BuildAuthenticationState(user); NotifyAuthenticationStateChanged(Task.FromResult(authState)); } public async Task Logout() { await ProtectedSessionStore.DeleteAsync("UserProfile"); NotifyAuthenticationStateChanged(Task.FromResult(Anonymous)); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } static AuthenticationState BuildAuthenticationState(UserProfile? userProfile) { if (userProfile is null) { return Anonymous; } else { var claims = new List<Claim> { }; claims.Add(new Claim(ClaimTypes.Name, userProfile.UserName)); return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt"))); } } } }
ILoginService.cs 代码
using BlazorServerCustomAuthTest.Models; namespace BlazorServerCustomAuthTest.Auth { public interface ILoginService { Task Login(UserProfile user); Task Logout(); } }
_Imports.razor 代码
@using System.Net.Http @using System.Net.Http.Json @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using static Microsoft.AspNetCore.Components.Web.RenderMode @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using BlazorServerCustomAuthTest @using BlazorServerCustomAuthTest.Components @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization
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 rel="stylesheet" href="app.css" /> <link rel="stylesheet" href="BlazorServerCustomAuthTest.styles.css" /> <HeadOutlet @rendermode="new InteractiveServerRenderMode( prerender: false )" /> </head> <body> <Routes @rendermode="new InteractiveServerRenderMode( prerender: false )" /> <script src="_framework/blazor.web.js"></script> </body> </html>
内容的提问来源于stack exchange,提问作者WinFXGuy
相关产品推荐
相关产品推荐

