Blazor自定义认证系统刷新页面后自动登出问题求助
刷新页面自动登出的问题修复方案
问题原因拆解
- 登录异步操作无效:你在
MarkUserAsAuthenticated里用Task.Run包裹SignInAsync,还没等它执行完成就通知了认证状态变更。Blazor Server环境下HttpContext仅在当前请求的上下文内有效,新开线程后HttpContext会变为null,等于SignInAsync根本没执行成功,浏览器没拿到认证Cookie,刷新后自然就登出了。 - 认证状态读取逻辑有漏洞:
GetAuthenticationStateAsync里仅当HttpContext.User已认证时才更新_currentUser,但没考虑HttpContext为空的情况(Blazor用SignalR交互时HttpContext会为空);而且每次刷新页面,CustomAuthenticationStateProvider会重新实例化,_currentUser会被重置为未认证状态。
具体修复步骤
1. 修改登录方法,移除多余线程
删掉Task.Run,直接等待SignInAsync完成,确保认证Cookie能正确写入浏览器:
public async Task MarkUserAsAuthenticated(string username, string role) { var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.Role, role) }, CookieAuthenticationDefaults.AuthenticationScheme); _currentUser = new ClaimsPrincipal(identity); var authProperties = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(60) }; // 直接等待SignInAsync执行完成,不要开启新线程 await _httpContextAccessor.HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, _currentUser, authProperties); NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(_currentUser))); }
2. 完善认证状态读取逻辑
确保无论HttpContext是否存在,都能正确返回用户状态:
public override Task<AuthenticationState> GetAuthenticationStateAsync() { ClaimsPrincipal user; // 仅当HttpContext存在且用户已认证时,使用HttpContext中的用户信息 if (_httpContextAccessor.HttpContext != null && _httpContextAccessor.HttpContext.User.Identity.IsAuthenticated) { user = _httpContextAccessor.HttpContext.User; _currentUser = user; } else { // 否则使用缓存的用户状态 user = _currentUser; } return Task.FromResult(new AuthenticationState(user)); }
3. 检查Program.cs的配置
确认已正确添加Cookie认证及相关服务:
// 添加Cookie认证配置 builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Login"; // 替换为你的登录页面路径 options.ExpireTimeSpan = TimeSpan.FromMinutes(60); options.SlidingExpiration = true; }); // 注册必要服务 builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>(); builder.Services.AddAuthorization();
4. 确认App.razor的授权组件包裹
确保路由被CascadingAuthenticationState包裹,让所有子组件能获取到认证状态:
<CascadingAuthenticationState> <Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <FocusOnNavigate RouteData="@routeData" Selector="h1" /> </Found> <NotFound> <PageTitle>Not found</PageTitle> <LayoutView Layout="@typeof(MainLayout)"> <p role="alert">抱歉,这个地址不存在。</p> </LayoutView> </NotFound> </Router> </CascadingAuthenticationState>
验证修复效果
登录后按F12打开开发者工具,切换到Application标签查看Cookie,确认存在.AspNetCore.Cookies的Cookie;刷新页面后再次检查该Cookie是否存在,同时验证页面是否保持登录状态。
内容的提问来源于stack exchange,提问作者Ensar Erdeve
相关产品推荐
相关产品推荐

