.NET 9 Blazor Server会话失效/过期检测及即时重定向实现需求
Blazor Server会话失效即时重定向解决方案
针对Blazor Server应用会话失效后无法及时重定向导致的交互卡顿、数据丢失问题,结合ASP.NET Core Identity和Cookie认证特性,可通过以下方案实现即时重定向至/inactive-session页面:
方案1:服务器端Circuit检测+SignalR推送
Blazor Server基于SignalR维护客户端与服务器的Circuit连接,通过自定义CircuitHandler跟踪会话状态,一旦检测到认证失效,立即向客户端推送重定向指令。
实现步骤:
- 自定义CircuitHandler,注入
IHttpContextAccessor和AuthenticationStateProvider跟踪认证状态:
public class SessionMonitoringCircuitHandler : CircuitHandler { private readonly IHttpContextAccessor _httpContextAccessor; private readonly AuthenticationStateProvider _authStateProvider; private Timer _sessionCheckTimer; public SessionMonitoringCircuitHandler(IHttpContextAccessor httpContextAccessor, AuthenticationStateProvider authStateProvider) { _httpContextAccessor = httpContextAccessor; _authStateProvider = authStateProvider; } public override async Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken) { // 启动定时检测任务,间隔建议设为比滑动过期时间短5分钟 _sessionCheckTimer = new Timer(async _ => await CheckSessionStatus(circuit), null, TimeSpan.Zero, TimeSpan.FromMinutes(1)); await base.OnConnectionUpAsync(circuit, cancellationToken); } private async Task CheckSessionStatus(Circuit circuit) { var authState = await _authStateProvider.GetAuthenticationStateAsync(); if (!authState.User.Identity.IsAuthenticated) { await circuit.SendAsync("RedirectToInactiveSession"); _sessionCheckTimer?.Dispose(); return; } // 验证Cookie是否已过期(适配滑动过期场景) var authCookie = _httpContextAccessor.HttpContext?.Request.Cookies[".AspNetCore.Identity.Application"]; if (authCookie != null) { var cookieOptions = _httpContextAccessor.HttpContext.RequestServices.GetRequiredService<IOptions<CookieAuthenticationOptions>>().Value; var ticket = cookieOptions.TicketDataFormat.Unprotect(authCookie); if (ticket?.Properties.ExpiresUtc < DateTimeOffset.UtcNow) { await circuit.SendAsync("RedirectToInactiveSession"); _sessionCheckTimer?.Dispose(); } } } public override async Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken) { _sessionCheckTimer?.Dispose(); await base.OnConnectionDownAsync(circuit, cancellationToken); } }
- 在Program.cs中注册CircuitHandler:
builder.Services.AddScoped<CircuitHandler, SessionMonitoringCircuitHandler>();
- 在
MainLayout.razor中注册SignalR消息监听:
@inject IJSRuntime JSRuntime @implements IAsyncDisposable @code { private IDisposable _redirectSubscription; protected override async Task OnInitializedAsync() { var hubConnection = await JSRuntime.InvokeAsync<HubConnection>("Blazor.platform.getHubConnection"); _redirectSubscription = hubConnection.On("RedirectToInactiveSession", async () => { await JSRuntime.InvokeVoidAsync("window.location.href", "/inactive-session"); }); await base.OnInitializedAsync(); } public async ValueTask DisposeAsync() { _redirectSubscription?.Dispose(); await Task.CompletedTask; } }
方案2:客户端定时心跳检测
客户端定期向服务器发送轻量级请求验证会话有效性,一旦检测失效立即重定向,实现简单且不依赖服务器推送逻辑。
实现步骤:
- 创建会话验证API端点:
[ApiController] [Route("api/[controller]")] public class SessionController : ControllerBase { [HttpGet("validate")] public IActionResult ValidateSession() { return User.Identity.IsAuthenticated ? Ok() : Unauthorized(); } }
- 在
MainLayout.razor中添加定时检测逻辑:
@inject HttpClient HttpClient @inject IJSRuntime JSRuntime @implements IAsyncDisposable @code { private Timer _heartbeatTimer; protected override void OnInitialized() { // 每分钟检测一次,可根据业务调整间隔 _heartbeatTimer = new Timer(async _ => await CheckSession(), null, TimeSpan.Zero, TimeSpan.FromMinutes(1)); base.OnInitialized(); } private async Task CheckSession() { try { var response = await HttpClient.GetAsync("/api/session/validate"); if (!response.IsSuccessStatusCode) { await JSRuntime.InvokeVoidAsync("window.location.href", "/inactive-session"); _heartbeatTimer?.Dispose(); } } catch (HttpRequestException) { // 网络问题导致无法连接,直接重定向 await JSRuntime.InvokeVoidAsync("window.location.href", "/inactive-session"); _heartbeatTimer?.Dispose(); } } public async ValueTask DisposeAsync() { _heartbeatTimer?.Dispose(); await Task.CompletedTask; } }
方案3:客户端Cookie过期检测
利用认证Cookie的过期时间,客户端JS定时检查剩余有效期,快过期时直接重定向,同时配合服务器端验证避免客户端篡改。
实现步骤:
- 在
_Host.cshtml中添加JS逻辑:
<script> function startSessionMonitoring() { setInterval(() => { const authCookie = document.cookie.split('; ').find(row => row.startsWith('.AspNetCore.Identity.Application=')); if (!authCookie) { window.location.href = '/inactive-session'; return; } // 解析Cookie过期时间(实际场景需匹配Cookie认证的序列化规则) const expiresMatch = document.cookie.match(/(^|;) ?.AspNetCore.Identity.Application=.*?; expires=([^;]+)/); if (expiresMatch && new Date(expiresMatch[2]) < new Date()) { window.location.href = '/inactive-session'; } }, 60000); // 每分钟检测一次 } window.addEventListener('load', startSessionMonitoring); </script>
- 关键操作前需补充服务器端认证状态检查,避免客户端篡改Cookie导致的误判。
注意事项
- 滑动过期场景下,需确保服务器端Cookie刷新逻辑正常,避免客户端检测与服务器状态不一致。
- 定时检测间隔需根据会话过期时间合理设置,过短增加服务器负载,过长则无法及时检测失效。
- 重定向时需确保Blazor Circuit已正确释放,避免资源泄漏。
内容的提问来源于stack exchange,提问作者MikeN
相关产品推荐
相关产品推荐

