You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:10:21