ASP.NET 8.0 Blazor Server表单提交后跳转至登录页问题
问题详情
我正在开发一个ASP.NET 8.0 Blazor Server应用,采用Microsoft Identity Framework Core实现授权功能,仅在用户登录成功后加载菜单项。我在NavMenu.razor和Home.razor组件中使用了如下授权逻辑:
<AuthorizeView> <Authorized> ........ </Authorized> <NotAuthorized> <Components.Account.Pages.Login> </Components.Account.Pages.Login> </NotAuthorized> </AuthorizeView>
应用启动时会要求用户登录,登录成功后侧边栏sidebar会显示菜单项,但当我在任意页面执行表单提交操作后,所有菜单项消失,页面跳转回登录页。以下是我的program.cs代码:
using GetTutorsOnline.Components; using GetTutorsOnline.Components.Account; using GetTutorsOnline.Data; using GTO.IModels.IModelRepos; using GTO.Infrastructure.Data; using GTO.Infrastructure.Repositories; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorComponents().AddInteractiveServerComponents(); builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped<IdentityUserAccessor>(); builder.Services.AddScoped<IdentityRedirectManager>(); builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>(); builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddIdentityCookies(); var conStr = builder.Configuration.GetConnectionString("DifriPediaSQLDb"); builder.Services.AddDbContextFactory<GTODbContext>(options => options.UseSqlServer(conStr)); builder.Services.AddDbContext<IdentityContext>(options => options.UseSqlServer(conStr)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddIdentityCore<GTOAppUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<IdentityContext>() .AddSignInManager() .AddDefaultTokenProviders(); builder.Services.AddSingleton<IEmailSender<GTOAppUser>, IdentityNoOpEmailSender>(); builder.Services.AddScoped<ISubjectNameRepo, SubjectNameRepo>(); builder.Services.AddScoped<IRegionRepo, RegionRepo>(); builder.Services.AddScoped<IAssessmentMonthRepo, AssessmentMonthRepo>(); builder.Services.AddScoped<IELevelRepo, ELevelRepo>(); builder.Services.AddScoped<ITeacherRepo, TeacherRepo>(); builder.Services.AddScoped<ICoordinatorRepo, CoordinatorRepo>(); builder.Services.AddScoped<IManagerRepo, ManagerRepo>(); builder.Services.AddScoped<IStudentRepo, StudentRepo>(); builder.Services.AddScoped<IParentRepo, ParentRepo>(); builder.Services.AddScoped<IEvaluationTweekRepo, EvaluationTweekRepo>(); builder.Services.AddScoped<ISubjectAllocationRepo, SubjectAllocationRepo>(); builder.Services.AddScoped<IDayNameRepo, DayNameRepo>(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAntiforgery(); //app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode(); app.MapAdditionalIdentityEndpoints(); app.Run();
解决方案
1. 恢复路由中间件
取消注释program.cs中的app.UseRouting();,Blazor Server依赖路由中间件来正确处理组件路由和身份验证上下文传递,缺失会导致身份状态在表单提交后丢失:
app.UseRouting(); app.UseAuthentication(); app.UseAuthorization();
2. 替换NotAuthorized块中的Login组件嵌入方式
直接在AuthorizeView的NotAuthorized块中嵌入Login组件会干扰身份状态管理,改用模板自带的RedirectToLogin组件实现登录跳转:
<NotAuthorized> <RedirectToLogin /> </NotAuthorized>
该组件会自动保存当前页面路径,登录成功后跳转回原页面,同时避免身份状态冲突。
3. 检查防伪令牌验证
Blazor Server表单提交必须通过防伪令牌验证,若令牌缺失或验证失败会触发身份验证失败。确保:
app.UseAntiforgery();位于UseStaticFiles()之后、UseAuthentication()之前- 表单使用Blazor交互式提交(
@onsubmit绑定)而非原生HTML表单提交,示例:
<form @onsubmit="HandleSubmit"> <!-- 表单字段 --> <button type="submit">提交</button> </form> @code { private async Task HandleSubmit() { // 业务逻辑处理 } }
4. 验证IdentityRevalidatingAuthenticationStateProvider行为
IdentityRevalidatingAuthenticationStateProvider会定期重新验证用户身份,若其实现逻辑有误,可能在表单提交后错误地将用户标记为未授权。检查该类的ValidateAuthenticationStateAsync方法,确保仅在必要时(如用户信息变更)触发重新验证,而非每次请求都执行。
5. 调整身份Cookie配置
确保身份验证Cookie的有效期和滑动过期设置合理,避免表单提交后Cookie意外过期:
builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddIdentityCookies(options => { options.ApplicationCookie.Configure(cookie => { cookie.ExpireTimeSpan = TimeSpan.FromHours(8); cookie.SlidingExpiration = true; cookie.HttpOnly = true; cookie.SecurePolicy = CookieSecurePolicy.Always; }); });
内容的提问来源于stack exchange,提问作者Fayyaz Ahmed

