Blazor Server+AWS Cognito+OIDC:Cookie过期自动登出异常问题
问题详情
我在Blazor Server结合OpenIDConnect和AWS Cognito的架构下,无法实现Cookie过期时自动登出用户的功能:
- 当前SignalR配置
在Program.cs中已设置SignalR在认证令牌过期时关闭连接:
// Configure SignalR to close the connection when the authentication token expires app.MapBlazorHub(options => { options.CloseOnAuthenticationExpiration = true; });
该配置能在Cookie过期时关闭SignalR连接,但由于OpenIDConnect和AWS Cognito的机制,连接断开后会立刻自动重建并获取新Cookie,导致用户始终保持登录状态。
- 尝试的CircuitHandler方案
我创建了CustomCircuitHandler服务捕获Circuit关闭事件,原本想在此处导航到/logout页面完成登出,但该服务没有PageModel的HTTP上下文,无法实现跳转:
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken) { // Implement logic to identify specific user and take actions Console.WriteLine($"Circuit closed for user: {circuit.Id}"); // Navigate to sign out page // NavigationManager.NavigateTo("/logout"); return Task.CompletedTask; }
- 已有的/logout页面
我的/logout页面代码如下,可完成Cookie和OpenIDConnect的登出:
public class LogOutModel : PageModel { public async Task OnGet() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" }); } }
解决方案
方案1:前端主动检测令牌过期并触发登出
在Blazor组件(推荐放在MainLayout.razor中)通过AuthenticationStateProvider监听用户状态,检测令牌过期时间,到期前主动导航到登出页面:
@inject AuthenticationStateProvider AuthStateProvider @inject NavigationManager NavManager @code { protected override async Task OnInitializedAsync() { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); var user = authState.User; if (user.Identity.IsAuthenticated) { // 从Cognito令牌的exp声明中获取过期时间 var expClaim = user.FindFirst("exp"); if (expClaim != null) { var expireTime = DateTimeOffset.FromUnixTimeSeconds(long.Parse(expClaim.Value)); var timeUntilExpire = expireTime - DateTimeOffset.UtcNow; // 提前5秒触发登出,避免令牌过期后才操作 var timer = new System.Timers.Timer(timeUntilExpire.TotalMilliseconds - 5000); timer.Elapsed += (sender, e) => { NavManager.NavigateTo("/logout", forceLoad: true); timer.Dispose(); }; timer.AutoReset = false; timer.Start(); } } } }
方案2:调整SignalR配置阻止自动重连
修改Program.cs中的SignalR配置,缩短断开超时时间,阻止连接过期后自动重建,这样Circuit关闭后用户会看到断开提示,此时手动引导到登出页面:
app.MapBlazorHub(options => { options.CloseOnAuthenticationExpiration = true; options.DisconnectedTimeout = TimeSpan.FromSeconds(0); // 禁止自动重连 options.ReconnectDelay = null; });
此方案会影响用户体验,仅推荐作为备选。
方案3:在CircuitHandler中通过HttpContext实现后端登出
先在Program.cs中注册IHttpContextAccessor:
builder.Services.AddHttpContextAccessor();
然后修改CustomCircuitHandler,注入IHttpContextAccessor并调用登出逻辑:
private readonly IHttpContextAccessor _httpContextAccessor; public CustomCircuitHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override async Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken) { var httpContext = _httpContextAccessor.HttpContext; if (httpContext != null && httpContext.User.Identity.IsAuthenticated) { await httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await httpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" }); } await base.OnCircuitClosedAsync(circuit, cancellationToken); }
注意:Blazor Server中Circuit的HttpContext可能并非当前用户的上下文,需充分测试验证。
内容的提问来源于stack exchange,提问作者Linas
相关产品推荐
相关产品推荐

