.NET 8 Blazor Server 2FA用户40分钟后断开及防伪令牌解密失败问题
解决Blazor Server 2FA用户40分钟后登录断开及Antiforgery报错问题
1. 显式配置Antiforgery Cookie有效期
Antiforgery令牌解密失败的核心原因是其关联Cookie默认有效期较短(与会话绑定),需单独配置与登录Cookie一致的30天有效期:
builder.Services.AddAntiforgery(options => { options.Cookie.Name = ".AspNetCore.Antiforgery"; options.Cookie.Expiration = TimeSpan.FromDays(30); options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 生产环境建议启用HTTPS options.Cookie.SameSite = SameSiteMode.Lax; });
2. 调整Blazor Server Circuit超时时间
Blazor Server默认Circuit超时为30分钟,超时后Circuit断开,重新交互时易触发Antiforgery验证失败,需延长Circuit相关配置:
builder.Services.AddServerSideBlazor(options => { options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromDays(1); // 保留断开的Circuit 1天 options.CircuitOptions.MaxRetainedCircuits = 100; // 根据服务器并发量调整 });
同时在_Host.cshtml中配置SignalR连接超时:
<script src="_framework/blazor.server.js"></script> <script> Blazor.start({ configureSignalR: function (builder) { builder.withUrl("/_blazor", { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets, timeout: 300000 // 设置为5分钟超时,按需调整 }); } }); </script>
3. 统一认证票据与Cookie配置
仅配置ApplicationCookie不够,需确保登录生成的认证票据有效期与Cookie对齐,同时覆盖外部OAuth登录的Cookie逻辑:
builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(options => { options.ExpireTimeSpan = TimeSpan.FromDays(30); options.SlidingExpiration = true; options.LoginPath = "/Login"; // 确保票据有效期与Cookie同步 options.Events = new CookieAuthenticationEvents { OnSigningIn = context => { context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddDays(30); context.Properties.IsPersistent = true; return Task.CompletedTask; } }; }) .AddGoogle(options => { // 填入你的Google OAuth配置 options.ClientId = "your-client-id"; options.ClientSecret = "your-client-secret"; // 复用主登录Cookie,避免外部登录Cookie单独过期 options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; });
4. 2FA验证后更新票据有效期
如果使用自定义2FA验证逻辑,需确保验证通过后生成的认证票据使用30天有效期:
// 示例:2FA验证通过后的登录代码 var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { ExpiresUtc = DateTimeOffset.UtcNow.AddDays(30), IsPersistent = true, AllowRefresh = true // 支持滑动过期刷新 }; await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
5. 配置心跳机制维持滑动过期
滑动过期需要用户主动交互才会刷新Cookie,若用户长时间无操作,可在主布局中添加定时心跳:
@implements IDisposable @code { private Timer _heartbeatTimer; protected override void OnInitialized() { // 每30分钟发送一次心跳请求,触发Cookie刷新 _heartbeatTimer = new Timer(async _ => { await Http.GetAsync("/api/heartbeat"); }, null, TimeSpan.Zero, TimeSpan.FromMinutes(30)); } public void Dispose() { _heartbeatTimer?.Dispose(); } }
同时添加对应的心跳API:
[ApiController] [Route("api/[controller]")] public class HeartbeatController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok(); } }
内容的提问来源于stack exchange,提问作者Christoff Colomb
相关产品推荐
相关产品推荐

