如何在ASP.NET Core 8.0 Blazor中结合外部API与JWT Token实现认证流程?
创建InteractiveAuto模式的Blazor应用对接自定义JWT API
1. 创建基础项目
用.NET CLI创建Interactive Auto模式的Blazor Web App:
dotnet new blazor -n MyJwtBlazorApp -int Auto
或在Visual Studio中选择「Blazor Web App」模板,交互模式选「Interactive Auto」,取消勾选「Enable Identity」(若默认勾选)。
2. 清理默认Identity内容
若创建时未取消Identity,手动清理:
- 删除
Pages/Account文件夹 - 在
Program.cs中移除Identity相关服务配置,比如AddDbContext<ApplicationDbContext>、AddDefaultIdentity、AddEntityFrameworkStores等代码块
3. 配置JWT认证服务
在Program.cs中添加适配自定义API的JWT认证配置:
builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "你的API发行者", ValidAudience = "你的API受众", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的API密钥")) }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); if (!string.IsNullOrEmpty(token)) { context.Token = token; } return Task.CompletedTask; } }; }); builder.Services.AddAuthorizationCore(); builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped<AuthenticationStateProvider, JwtAuthenticationStateProvider>();
4. 自定义AuthenticationStateProvider
创建JwtAuthenticationStateProvider.cs,处理客户端与服务器端的认证状态同步:
public class JwtAuthenticationStateProvider : AuthenticationStateProvider { private readonly HttpClient _httpClient; private readonly IJSRuntime _jsRuntime; public JwtAuthenticationStateProvider(HttpClient httpClient, IJSRuntime jsRuntime) { _httpClient = httpClient; _jsRuntime = jsRuntime; } public override async Task<AuthenticationState> GetAuthenticationStateAsync() { var token = string.Empty; #if WASM token = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "authToken"); #else var authHeader = _httpClient.DefaultRequestHeaders.Authorization; token = authHeader?.Parameter; #endif if (string.IsNullOrEmpty(token)) { return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); } var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadJwtToken(token); var claims = jwtToken.Claims.ToList(); var identity = new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme); var user = new ClaimsPrincipal(identity); return new AuthenticationState(user); } public void UpdateAuthenticationState(string token) { #if WASM _jsRuntime.InvokeVoidAsync("localStorage.setItem", "authToken", token); #endif NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } }
5. 实现登录组件
创建Pages/Login.razor,对接API获取JWT并更新认证状态:
@page "/login" @inject HttpClient Http @inject AuthenticationStateProvider AuthStateProvider @inject NavigationManager NavManager <h3>登录</h3> <div class="login-form"> <label>用户名:</label> <input @bind="Username" class="form-input" /> </div> <div class="login-form"> <label>密码:</label> <input type="password" @bind="Password" class="form-input" /> </div> <button @onclick="Login" class="login-btn">登录</button> @code { private string Username { get; set; } private string Password { get; set; } private async Task Login() { var loginModel = new { Username, Password }; var response = await Http.PostAsJsonAsync("你的API登录接口地址", loginModel); if (response.IsSuccessStatusCode) { var token = await response.Content.ReadAsStringAsync(); ((JwtAuthenticationStateProvider)AuthStateProvider).UpdateAuthenticationState(token); NavManager.NavigateTo("/"); } else { // 处理登录失败逻辑,比如提示错误 } } }
6. 配置路由与授权
修改App.razor,确保认证状态正确传递并处理授权逻辑:
<CascadingAuthenticationState> <Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"> <NotAuthorized> @if (!context.User.Identity.IsAuthenticated) { <RedirectToLogin /> } else { <p>你没有权限访问此页面。</p> } </NotAuthorized> </AuthorizeRouteView> <FocusOnNavigate RouteData="@routeData" Selector="h1" /> </Found> <NotFound> <PageTitle>页面不存在</PageTitle> <LayoutView Layout="@typeof(MainLayout)"> <p>抱歉,找不到你要访问的页面。</p> </LayoutView> </NotFound> </Router> </CascadingAuthenticationState>
7. 客户端请求自动携带Token
创建JwtAuthorizationHandler.cs,让客户端HttpClient自动添加Authorization头:
public class JwtAuthorizationHandler : DelegatingHandler { private readonly IJSRuntime _jsRuntime; public JwtAuthorizationHandler(IJSRuntime jsRuntime) { _jsRuntime = jsRuntime; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var token = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "authToken"); if (!string.IsNullOrEmpty(token)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); } return await base.SendAsync(request, cancellationToken); } }
在客户端项目(.Client文件夹下的Program.cs)中注册:
builder.Services.AddScoped<JwtAuthorizationHandler>(); builder.Services.AddHttpClient("ApiClient", client => client.BaseAddress = new Uri("你的API基础地址")) .AddHttpMessageHandler<JwtAuthorizationHandler>();
内容的提问来源于stack exchange,提问作者Ketankumar Godhani
相关产品推荐
相关产品推荐

