Blazor Server自定义认证:登录后授权访问<Authorized>标签内容
Blazor Server自定义登录与授权实现
要实现自定义登录并让用户访问<Authorized>标签内容,核心是通过**自定义AuthenticationStateProvider**管理用户认证状态,结合登录服务完成API验证与状态更新,具体步骤如下:
1. 实现自定义AuthenticationStateProvider
创建继承自AuthenticationStateProvider的类,负责维护当前用户的认证状态,并提供状态更新的方法:
using Microsoft.AspNetCore.Components.Authorization; using System.Security.Claims; namespace AdminFrontend.Services { public class CustomAuthStateProvider : AuthenticationStateProvider { // 存储当前认证用户的ClaimsPrincipal private ClaimsPrincipal _currentUser = new ClaimsPrincipal(new ClaimsIdentity()); // 返回当前认证状态 public override Task<AuthenticationState> GetAuthenticationStateAsync() { return Task.FromResult(new AuthenticationState(_currentUser)); } // 登录成功后更新用户状态 public void UpdateAuthenticationState(User user, List<string>? roles = null) { // 创建用户身份标识,添加邮箱、手机号等声明 var claims = new List<Claim> { new Claim(ClaimTypes.Email, user.email), new Claim(ClaimTypes.MobilePhone, user.mobilenumber) }; // 若有角色,添加角色声明 if (roles != null) { claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r))); } var identity = new ClaimsIdentity(claims, "CustomAuth"); _currentUser = new ClaimsPrincipal(identity); // 通知Blazor框架状态变更,触发页面重新授权检查 NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } // 登出时重置状态 public void Logout() { _currentUser = new ClaimsPrincipal(new ClaimsIdentity()); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } } }
2. 创建登录服务封装API验证逻辑
编写登录服务,负责调用后端API验证用户信息,返回验证结果并更新认证状态:
using System.Net.Http.Json; namespace AdminFrontend.Services { public class AuthService { private readonly HttpClient _httpClient; private readonly CustomAuthStateProvider _authStateProvider; public AuthService(HttpClient httpClient, CustomAuthStateProvider authStateProvider) { _httpClient = httpClient; _authStateProvider = authStateProvider; } // 调用API验证登录,成功则更新认证状态 public async Task<bool> Login(User user) { try { // 调用后端登录API,假设返回包含用户角色的响应 var response = await _httpClient.PostAsJsonAsync("api/auth/login", user); if (response.IsSuccessStatusCode) { // 从API响应获取用户角色(根据实际接口调整) var loginResult = await response.Content.ReadFromJsonAsync<LoginResponse>(); // 更新认证状态 _authStateProvider.UpdateAuthenticationState(user, loginResult?.Roles); return true; } return false; } catch { return false; } } // 登出方法 public void Logout() { _authStateProvider.Logout(); } } // 适配API返回的登录结果模型(根据实际接口调整) public class LoginResponse { public List<string>? Roles { get; set; } // 可添加令牌、用户ID等其他字段 } }
3. 在Program.cs中注册服务
将自定义的认证状态提供者和登录服务注入到依赖容器:
using AdminFrontend.Services; using Microsoft.AspNetCore.Components.Authorization; var builder = WebApplication.CreateBuilder(args); // 添加Blazor组件服务 builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); // 注册HttpClient builder.Services.AddHttpClient(); // 注册自定义认证状态提供者和登录服务 builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>(); builder.Services.AddScoped<AuthService>(); var app = builder.Build(); // ... 中间件配置省略 ... app.Run();
4. 登录组件实现逻辑
在自定义登录表单组件中,调用AuthService完成登录,成功后跳转页面:
@page "/login" @inject AuthService AuthService @inject NavigationManager NavManager <h3>登录</h3> <div> <input type="email" @bind="@user.email" placeholder="邮箱" /> <input type="password" @bind="@user.password" placeholder="密码" /> <input type="text" @bind="@user.mobilenumber" placeholder="手机号" /> <input type="text" @bind="@user.service" placeholder="服务标识" /> <button @onclick="HandleLogin">登录</button> </div> @code { private User user = new User(); private async Task HandleLogin() { bool loginSuccess = await AuthService.Login(user); if (loginSuccess) { // 登录成功后跳转至主页或指定页面 NavManager.NavigateTo("/"); } else { // 登录失败提示 Console.WriteLine("登录失败,请检查账号密码"); } } }
5. 导航菜单与授权控制
使用<AuthorizeView>组件控制导航菜单的显示,登录后自动切换菜单内容:
<NavMenu> <AuthorizeView> <Authorized> <div class="nav-item px-3"> <NavLink class="nav-link" href="/dashboard"> <span class="oi oi-dashboard" aria-hidden="true"></span> 控制台 </NavLink> </div> <div class="nav-item px-3"> <button class="nav-link" @onclick="() => AuthService.Logout()"> <span class="oi oi-account-logout" aria-hidden="true"></span> 登出 </button> </div> </Authorized> <NotAuthorized> <div class="nav-item px-3"> <NavLink class="nav-link" href="/login"> <span class="oi oi-account-login" aria-hidden="true"></span> 登录 </NavLink> </div> </NotAuthorized> </AuthorizeView> </NavMenu> @code { [Inject] private AuthService AuthService { get; set; } }
6. 保护页面内容
在需要授权的页面或组件中,使用<Authorize>标签或<AuthorizeView>保护内容:
@page "/dashboard" @attribute [Authorize] <h1>控制台</h1> <p>仅登录用户可查看此内容</p>
关键说明
CustomAuthStateProvider通过NotifyAuthenticationStateChanged方法通知框架状态变更,触发页面重新进行授权检查,从而自动更新<Authorized>和<NotAuthorized>区域的内容。- 如果API返回JWT令牌,可将令牌存储在
LocalStorage或SessionStorage中,在CustomAuthStateProvider初始化时读取令牌并恢复用户状态(适合持久化登录场景)。 - 角色授权可通过
[Authorize(Roles = "Admin")]属性实现,只需在UpdateAuthenticationState中添加对应的角色声明即可。
内容的提问来源于stack exchange,提问作者obind
相关产品推荐
相关产品推荐

