.NET 8身份验证API能否用于Blazor?及后续实现方法
问题解答
可行性说明
完全可行,你可以通过自定义登录流程,将用户名密码发送到自己搭建的.NET 8身份验证API获取JWT令牌,之后在Blazor应用中管理令牌并实现身份验证逻辑,无需依赖脚手架生成的Area/Identity页面。
Blazor Server 实现流程
1. 自定义身份状态管理
创建自定义AuthenticationStateProvider来管理令牌和用户身份,推荐结合Blazored.LocalStorage存储令牌(需安装对应NuGet包):
public class CustomAuthStateProvider : AuthenticationStateProvider { private readonly HttpClient _httpClient; private readonly ILocalStorageService _localStorage; public CustomAuthStateProvider(HttpClient httpClient, ILocalStorageService localStorage) { _httpClient = httpClient; _localStorage = localStorage; } public override async Task<AuthenticationState> GetAuthenticationStateAsync() { var token = await _localStorage.GetItemAsync<string>("authToken"); var identity = new ClaimsIdentity(); if (!string.IsNullOrEmpty(token)) { var claims = ParseClaimsFromJwt(token); identity = new ClaimsIdentity(claims, "jwt"); } var user = new ClaimsPrincipal(identity); return new AuthenticationState(user); } public async Task LoginAsync(string token) { await _localStorage.SetItemAsync("authToken", token); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } public async Task LogoutAsync() { await _localStorage.RemoveItemAsync("authToken"); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } private IEnumerable<Claim> ParseClaimsFromJwt(string jwt) { var payload = jwt.Split('.')[1]; var jsonBytes = ParseBase64WithoutPadding(payload); var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes); return keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())); } private byte[] ParseBase64WithoutPadding(string base64) { switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } return Convert.FromBase64String(base64); } }
2. 自定义登录页面逻辑
在自己的登录Blazor页面中,调用API获取令牌并触发身份状态更新:
@page "/login" @inject HttpClient Http @inject CustomAuthStateProvider AuthStateProvider @inject NavigationManager NavManager <div class="login-form"> <input @bind="Username" placeholder="用户名" class="form-input" /> <input @bind="Password" type="password" placeholder="密码" class="form-input" /> <button @onclick="HandleLogin" class="login-btn">登录</button> @if (!string.IsNullOrEmpty(ErrorMessage)) { <p class="error-message">@ErrorMessage</p> } </div> @code { private string Username { get; set; } private string Password { get; set; } private string ErrorMessage { get; set; } private async Task HandleLogin() { ErrorMessage = string.Empty; var loginRequest = new { Username = Username, Password = Password }; var response = await Http.PostAsJsonAsync("/api/auth/login", loginRequest); if (response.IsSuccessStatusCode) { var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>(); await AuthStateProvider.LoginAsync(tokenResponse.AccessToken); NavManager.NavigateTo("/"); } else { ErrorMessage = "用户名或密码错误"; } } private class TokenResponse { public string AccessToken { get; set; } } }
3. 配置服务与路由保护
在Program.cs中注册自定义服务:
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>(); builder.Services.AddBlazoredLocalStorage(); builder.Services.AddAuthorizationCore();
使用AuthorizeRouteView保护需要登录的页面:
<Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"> <NotAuthorized> <RedirectToLogin /> </NotAuthorized> </AuthorizeRouteView> </Found> <NotFound> <LayoutView Layout="@typeof(MainLayout)"> <p>抱歉,该页面不存在</p> </LayoutView> </NotFound> </Router>
Blazor Hybrid(MAUI Blazor)实现流程
流程与Blazor Server类似,主要差异在于令牌存储方式,改用MAUI内置的Preferences或SecureStorage:
1. 调整身份状态管理
public class HybridAuthStateProvider : AuthenticationStateProvider { private readonly HttpClient _httpClient; public HybridAuthStateProvider(HttpClient httpClient) { _httpClient = httpClient; } public override async Task<AuthenticationState> GetAuthenticationStateAsync() { var token = SecureStorage.GetAsync("authToken").Result; var identity = new ClaimsIdentity(); if (!string.IsNullOrEmpty(token)) { var claims = ParseClaimsFromJwt(token); identity = new ClaimsIdentity(claims, "jwt"); } var user = new ClaimsPrincipal(identity); return new AuthenticationState(user); } public async Task LoginAsync(string token) { await SecureStorage.SetAsync("authToken", token); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } public async Task LogoutAsync() { await SecureStorage.RemoveAsync("authToken"); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } // 复用ParseClaimsFromJwt和ParseBase64WithoutPadding方法 }
2. 配置服务
builder.Services.AddScoped<AuthenticationStateProvider, HybridAuthStateProvider>(); builder.Services.AddAuthorizationCore();
关键注意事项
- 令牌过期处理:API返回令牌时携带过期时间,在Blazor中定时检查,过期后自动跳转登录页。
- 请求自动携带令牌:创建
DelegatingHandler拦截HTTP请求,自动添加Authorization: Bearer {token}头,避免每个请求手动设置。 - 安全存储:Blazor Hybrid中优先使用
SecureStorage存储令牌,避免明文存储敏感数据。
内容的提问来源于stack exchange,提问作者Bennyboy1973
相关产品推荐
相关产品推荐

