ASP.NET Core Identity中Microsoft认证的Cookie持久化问题
问题描述
在Blazor WebApp中使用个人登录与Microsoft认证功能,调试时希望无需每次打开应用都重新登录。目前个人账号登录时Cookie可正常持久化,但Microsoft账号登录后浏览器未存储持久化Cookie,关闭浏览器再打开需重新登录。
解决方案
问题根源在于默认情况下,外部登录(如Microsoft账号)使用的IdentityConstants.ExternalScheme Cookie是会话级Cookie,关闭浏览器后会自动失效。需通过以下两步修改实现持久化:
1. 配置外部登录Cookie为持久化
在AddIdentityCookies中显式配置ExternalCookie的过期时间与持久化属性:
builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddMicrosoftAccount(microsoftOptions => { microsoftOptions.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"]; microsoftOptions.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"]; }) .AddIdentityCookies(cookieOptions => { // 配置外部登录Cookie为持久化 cookieOptions.ExternalCookie.Configure(opt => { opt.ExpireTimeSpan = TimeSpan.FromDays(7); // 可根据需求调整有效期 opt.SlidingExpiration = true; // 用户活动时自动刷新Cookie过期时间 opt.Cookie.IsPersistent = true; // 标记Cookie为持久化类型 }); });
2. 确保登录时设置持久化标记
在外部登录的回调逻辑中,调用SignInManager.SignInAsync时传入isPersistent: true。默认模板中需修改Account/ExternalLogin.razor.cs里的登录确认方法,确保代码如下:
await _signInManager.SignInAsync(user, isPersistent: true);
修改后的完整代码
using BlazorApp1.Components; using BlazorApp1.Components.Account; using BlazorApp1.Data; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); // Add services to the container. 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; }).AddMicrosoftAccount(microsoftOptions => { microsoftOptions.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"]; microsoftOptions.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"]; }) .AddIdentityCookies(cookieOptions => { // 配置外部登录Cookie为持久化 cookieOptions.ExternalCookie.Configure(opt => { opt.ExpireTimeSpan = TimeSpan.FromDays(7); opt.SlidingExpiration = true; opt.Cookie.IsPersistent = true; }); }); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>() .AddSignInManager() .AddDefaultTokenProviders(); builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseMigrationsEndPoint(); } else { app.UseExceptionHandler("/Error", createScopeForErrors: true); // The default HSTS value is 30 days. You may want to change this for production scenarios. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAntiforgery(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode(); // Add additional endpoints required by the Identity /Account Razor components. app.MapAdditionalIdentityEndpoints(); app.Run();
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

