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

Blazor Server不依赖HttpContext实现会话超时方案求助

不依赖HttpContext的Blazor Server会话超时实现方案

方案1:Scoped状态服务+组件级活动跟踪

完全基于Blazor内置机制实现,无需依赖HttpContext或JS互操作,通过Scoped服务跟踪用户活动状态,结合组件事件和定时器触发超时逻辑。

步骤1:创建会话超时状态服务

创建Scoped服务用于管理用户最后活动时间、超时阈值,并提供超时通知能力:

public class SessionTimeoutService
{
    private readonly TimeSpan _timeout = TimeSpan.FromMinutes(20);
    public DateTime LastActivityTime { get; private set; } = DateTime.UtcNow;
    public event Action OnSessionTimeout;

    public void UpdateLastActivity()
    {
        LastActivityTime = DateTime.UtcNow;
    }

    public bool IsSessionTimedOut()
    {
        return DateTime.UtcNow - LastActivityTime >= _timeout;
    }

    public void TriggerTimeout()
    {
        OnSessionTimeout?.Invoke();
    }
}

在Program.cs中注册为Scoped服务:

builder.Services.AddScoped<SessionTimeoutService>();

步骤2:全局布局组件实现活动跟踪

在主布局组件(如MainLayout.razor)的根元素绑定Blazor内置交互事件,实时更新用户活动状态,并启动定时检查:

@inherits LayoutComponentBase
@inject SessionTimeoutService SessionTimeoutService
@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthStateProvider

<div class="page" 
     @onmousemove="HandleUserInteraction" 
     @onclick="HandleUserInteraction" 
     @onkeydown="HandleUserInteraction">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

@code {
    private System.Timers.Timer _timeoutTimer;

    protected override void OnInitialized()
    {
        SessionTimeoutService.OnSessionTimeout += HandleSessionTimeout;
        
        // 每30秒检查一次超时状态
        _timeoutTimer = new System.Timers.Timer(30000);
        _timeoutTimer.Elapsed += CheckSessionTimeout;
        _timeoutTimer.Start();

        base.OnInitialized();
    }

    private void HandleUserInteraction()
    {
        SessionTimeoutService.UpdateLastActivity();
    }

    private void CheckSessionTimeout(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (SessionTimeoutService.IsSessionTimedOut())
        {
            _timeoutTimer.Stop();
            InvokeAsync(SessionTimeoutService.TriggerTimeout);
        }
    }

    private async Task HandleSessionTimeout()
    {
        // 结合自身认证系统执行登出逻辑,示例为自定义AuthStateProvider
        if (AuthStateProvider is CustomAuthStateProvider customAuth)
        {
            await customAuth.MarkUserAsLoggedOut();
        }
        
        // 强制导航到登录页,避免客户端缓存
        NavigationManager.NavigateTo("/login", forceLoad: true);
    }

    public void Dispose()
    {
        _timeoutTimer?.Dispose();
        SessionTimeoutService.OnSessionTimeout -= HandleSessionTimeout;
    }
}

方案2:结合Blazor Circuit生命周期配置

将自定义活动跟踪与Blazor Circuit内置超时机制结合,实现双重保障:

步骤1:配置Circuit超时参数

在Program.cs中设置Circuit空闲超时和断开连接保留时间:

builder.Services.AddServerSideBlazor()
    .AddCircuitOptions(options => 
    {
        // 设置断开连接后Circuit保留时间为20分钟
        options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(20);
        // 设置空闲19分钟时触发警告事件
        options.CircuitIdleTimeout = TimeSpan.FromMinutes(19);
    });

步骤2:创建Circuit Handler监听空闲事件

自定义Circuit Handler,在Circuit空闲时检查会话状态:

public class SessionCircuitHandler : CircuitHandler
{
    private readonly SessionTimeoutService _sessionTimeoutService;

    public SessionCircuitHandler(SessionTimeoutService sessionTimeoutService)
    {
        _sessionTimeoutService = sessionTimeoutService;
    }

    public override Task OnCircuitIdleAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        if (_sessionTimeoutService.IsSessionTimedOut())
        {
            _sessionTimeoutService.TriggerTimeout();
        }
        return base.OnCircuitIdleAsync(circuit, cancellationToken);
    }
}

注册Circuit Handler:

builder.Services.AddScoped<CircuitHandler, SessionCircuitHandler>();

注意事项

  • Scoped服务与用户Circuit绑定,每个用户拥有独立状态实例,不会出现跨用户状态混淆。
  • 定时器检查间隔可根据服务器资源情况调整,比如改为1分钟一次。
  • 登出逻辑需结合自身认证系统,若使用ASP.NET Core Identity,需调用SignOutManager的登出方法清除认证Cookie。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:10:36