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

Blazor 8交互式服务器认证:Cookie过期未自动登出问题求助

在Blazor Interactive Server中,默认的IdentityRevalidatingAuthenticationStateProvider仅验证用户的SecurityStamp,不会主动检查客户端的认证Cookie是否存在或过期。由于Blazor Server的认证状态是在服务器端SignalR连接中维护的,即使客户端Cookie被删除/过期,服务器端仍会保留之前的认证状态,直到触发重验证逻辑。

以下是解决这个问题的具体方案:

1. 扩展认证状态提供器,增加Cookie有效性检查

修改你的IdentityRevalidatingAuthenticationStateProvider,注入IHttpContextAccessor来获取当前请求的Cookie,在验证流程中先检查Cookie是否存在:

internal sealed class IdentityRevalidatingAuthenticationStateProvider(
    ILoggerFactory loggerFactory,
    IServiceScopeFactory scopeFactory,
    IOptions<IdentityOptions> options,
    IHttpContextAccessor httpContextAccessor)
    : RevalidatingServerAuthenticationStateProvider(loggerFactory)
{
    private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor;
    protected override TimeSpan RevalidationInterval => TimeSpan.FromMinutes(1);

    protected override async Task<bool> ValidateAuthenticationStateAsync(
        AuthenticationState authenticationState, CancellationToken cancellationToken)
    {
        // 先检查当前请求是否携带有效认证Cookie
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext == null)
        {
            return false;
        }

        var authCookie = httpContext.Request.Cookies[IdentityConstants.ApplicationScheme];
        if (string.IsNullOrEmpty(authCookie))
        {
            // Cookie不存在,直接判定验证失败
            return false;
        }

        // 原有SecurityStamp验证逻辑
        await using var scope = scopeFactory.CreateAsyncScope();
        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        return await ValidateSecurityStampAsync(userManager, authenticationState.User);
    }

    private async Task<bool> ValidateSecurityStampAsync(UserManager<ApplicationUser> userManager, ClaimsPrincipal principal)
    {
        var user = await userManager.GetUserAsync(principal);
        if (user is null)
        {
            return false;
        }
        else if (!userManager.SupportsUserSecurityStamp)
        {
            return true;
        }
        else
        {
            var principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType);
            var userStamp = await userManager.GetSecurityStampAsync(user);
            return principalStamp == userStamp;
        }
    }        
}

记得在Program.cs中注册IHttpContextAccessor:

builder.Services.AddHttpContextAccessor();

2. 页面导航时主动触发重验证

为了让用户在切换页面时立即感知认证状态变化,在布局组件中订阅导航事件,触发重验证:

@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthStateProvider
@implements IDisposable

@code {
    protected override void OnInitialized()
    {
        NavigationManager.LocationChanged += HandleLocationChanged;
    }

    private async void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
    {
        if (AuthStateProvider is RevalidatingServerAuthenticationStateProvider revalidatingProvider)
        {
            await revalidatingProvider.RevalidateAuthenticationStateAsync();
        }
    }

    public void Dispose()
    {
        NavigationManager.LocationChanged -= HandleLocationChanged;
    }
}

3. 增强Cookie验证事件(可选)

在Cookie配置中添加OnValidatePrincipal事件,进一步确保Cookie过期时主动失效认证状态:

builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
    options.SlidingExpiration = true;

    options.Events.OnValidatePrincipal = async context =>
    {
        var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
        var user = await userManager.GetUserAsync(context.Principal);
        
        if (user == null || !await userManager.IsValidSecurityStampAsync(context.Principal))
        {
            context.RejectPrincipal();
            await context.HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
        }
    };
});

效果说明

  • 当Cookie过期或被删除后,下一次重验证(定时1分钟或页面导航时)会检测到Cookie缺失,返回验证失败,服务器端会更新认证状态为未登录。
  • 页面导航时的主动重验证能让用户立即看到登出效果,无需等待定时重验证触发。

内容的提问来源于stack exchange,提问作者Muheeb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:42:09