强制Blazor Web App每次启动时重新登录(不保留会话登录信息)
解决Blazor Web App重启后保留登录状态,强制重新登录的问题
问题根源
你当前代码中仅清除了外部登录Scheme的Cookie(IdentityConstants.ExternalScheme),但你的应用实际使用的是Identity默认的应用认证Scheme(IdentityConstants.ApplicationScheme),所以重启后客户端存储的认证Cookie依然有效,导致自动登录。同时你的LoginUser方法存在逻辑错误:无论登录成功与否都会执行跳转,可能引发异常或不符合预期的页面跳转。
解决方案1:修改登录页,清除默认认证Cookie
直接在登录页初始化时清除应用认证Scheme的Cookie,确保用户进入登录页时处于完全登出状态:
修改Login.Razor的OnInitializedAsync方法:
protected override async Task OnInitializedAsync() { Input ??= new(); ReturnUrl ??= "/"; if (HttpMethods.IsGet(HttpContext.Request.Method)) { // 清除默认应用认证Cookie,强制重新登录 await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme); // 同时清除外部登录Cookie(如有外部登录需求) await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); } }
同时修正LoginUser方法的跳转逻辑,仅在登录成功时执行跳转:
public async Task LoginUser() { var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false); if (result.Succeeded) { SharedAppData.LoggedInThisSession = true; Logger.LogInformation("User logged in."); // 仅登录成功时跳转 RedirectManager.RedirectTo(ReturnUrl); } else if (result.RequiresTwoFactor) { RedirectManager.RedirectTo( "/Account/LoginWith2fa", new() { ["ReturnUrl"] = ReturnUrl, ["RememberMe"] = Input.RememberMe }); } else if (result.IsLockedOut) { Logger.LogWarning("User account locked out."); RedirectManager.RedirectTo("/Account/Lockout"); } else { errorMessage = "Error: Invalid login attempt."; } }
解决方案2:全局强制应用重启后登出所有用户
如果需要无论用户是否访问登录页,只要应用重启就强制所有用户重新登录,可以通过跟踪应用启动时间,在认证时验证Cookie中的启动时间是否与当前一致:
- 在
Program.cs中添加应用启动时间,并配置Cookie认证事件:
var builder = WebApplication.CreateBuilder(args); // 记录应用启动时间(精确到秒,确保每次重启都不同) var appStartTime = DateTime.UtcNow.ToString("yyyyMMddHHmmss"); // 注册服务... builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Cookie.HttpOnly = true; options.ExpireTimeSpan = TimeSpan.FromMinutes(30); options.LoginPath = "/Account/Login"; options.AccessDeniedPath = "/Account/AccessDenied"; // 登录时存储当前应用启动时间到Cookie属性 options.Events.OnSigningIn = context => { context.Properties.Items["AppStartTime"] = appStartTime; // 强制使用Session Cookie,关闭浏览器自动失效(可选) context.Properties.IsPersistent = false; return Task.CompletedTask; }; // 验证Cookie时检查应用启动时间是否匹配 options.Events.OnValidatePrincipal = context => { var currentAppStartTime = context.HttpContext.Items["AppStartTime"] as string; var storedAppStartTime = context.Properties.Items.TryGetValue("AppStartTime", out var value) ? value : null; if (storedAppStartTime != currentAppStartTime) { // 应用已重启,拒绝当前认证并登出 context.RejectPrincipal(); return context.HttpContext.SignOutAsync(options.Cookie.Name); } return Task.CompletedTask; }; }); var app = builder.Build(); // 添加中间件,将应用启动时间注入到HttpContext app.Use(async (context, next) => { context.Items["AppStartTime"] = appStartTime; await next(); }); // 其他中间件配置... app.Run();
额外说明
- 解决方案1适合仅在用户进入登录页时强制登出,用户直接访问授权页时仍会自动跳转登录并清除Cookie;
- 解决方案2适合全局强制,只要应用重启,所有持有旧Cookie的用户都会被强制登出,无论访问哪个页面;
- 如果不需要
RememberMe功能,可以直接在PasswordSignInAsync中将第三个参数固定为false,避免生成持久化Cookie。
内容的提问来源于stack exchange,提问作者CraigInCali
相关产品推荐
相关产品推荐

