如何在Blazor WebAssembly中实现未登录禁止页面导航的认证?
Blazor 未登录禁止页面导航的认证实现方案
一、自定义 AuthenticationStateProvider
默认的AuthenticationStateProvider无法适配你的自定义登录逻辑,需要自己实现状态管理:
using Microsoft.AspNetCore.Components.Authorization; using System.Security.Claims; using System.Threading.Tasks; public class CustomAuthStateProvider : AuthenticationStateProvider { private ClaimsPrincipal _currentUser; public CustomAuthStateProvider() { // 初始化未登录状态 _currentUser = new ClaimsPrincipal(new ClaimsIdentity()); } // 更新为已登录状态 public void MarkUserAsAuthenticated(string userEmail) { var claims = new[] { new Claim(ClaimTypes.Email, userEmail) }; _currentUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "CustomAuth")); // 通知所有组件认证状态变更 NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } // 更新为未登录状态 public void MarkUserAsLoggedOut() { _currentUser = new ClaimsPrincipal(new ClaimsIdentity()); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } public override Task<AuthenticationState> GetAuthenticationStateAsync() { return Task.FromResult(new AuthenticationState(_currentUser)); } }
二、注册服务
在Program.cs中替换默认的认证状态服务:
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>(); builder.Services.AddAuthorizationCore();
三、修改登录逻辑
登录成功后同步更新认证状态:
[Inject] protected NavigationManager NavigationManager { get; set; } [Inject] protected CustomAuthStateProvider AuthStateProvider { get; set; } protected async Task HandleSubmit() { Boolean success = await databaseclient.AuthenticateUserAsync(Email, Password); if (success) { // 标记用户已登录 AuthStateProvider.MarkUserAsAuthenticated(Email); // 处理返回地址,无返回地址则跳转到首页 var returnUrl = NavigationManager.GetQueryParameter("returnUrl"); NavigationManager.NavigateTo(string.IsNullOrEmpty(returnUrl) ? "/startseite" : returnUrl); } else { ErrorMessage = "Authentication failed. Please check your credentials."; } }
四、路由级权限控制
在App.razor中用AuthorizeRouteView包裹路由,拦截未登录访问:
<CascadingAuthenticationState> <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>Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router> </CascadingAuthenticationState>
五、实现跳转登录组件
创建RedirectToLogin.razor,处理未登录时的跳转逻辑:
@inject NavigationManager NavigationManager @code { protected override void OnInitialized() { // 记录当前访问的页面,登录后自动跳转回来 var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); NavigationManager.NavigateTo($"login?returnUrl={Uri.EscapeDataString(returnUrl)}"); } }
六、全局导航拦截(可选)
在MainLayout.razor中监听导航事件,防止用户直接输入URL跳转:
@inject NavigationManager NavigationManager @inject AuthenticationStateProvider AuthStateProvider @implements IDisposable @code { private IDisposable _navigationSubscription; protected override void OnInitialized() { _navigationSubscription = NavigationManager.LocationChanging += OnLocationChanging; } private async void OnLocationChanging(object sender, LocationChangingEventArgs e) { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); var isAuthenticated = authState.User.Identity?.IsAuthenticated ?? false; // 定义公开访问的路由(无需登录即可访问) var publicRoutes = new[] { "/login", "/register", "/" }; var targetPath = NavigationManager.ToBaseRelativePath(e.Location); // 未登录且访问非公开路由时,拦截导航并跳转登录页 if (!isAuthenticated && !publicRoutes.Contains(targetPath)) { e.Cancel = true; NavigationManager.NavigateTo($"login?returnUrl={Uri.EscapeDataString(targetPath)}"); } } public void Dispose() { _navigationSubscription?.Dispose(); } }
内容的提问来源于stack exchange,提问作者benenbred
相关产品推荐
相关产品推荐

