清除浏览器Cookie无法登出Azure AD,Cookie过期未触发强制重登问题
问题与解决方案
问题描述
我在program.cs的Azure AD配置中设置了Cookie过期策略,但存在以下问题:
- Cookie无论是否过期,刷新页面都会重新加载所有Cookie,不会强制用户重新登录
- 清除浏览器所有Cookie后,用户仍未从Azure AD中登出
- Cookie失效后,调用带
[Authorize]标签的控制器API时出现CORS错误,期望Cookie失效时强制用户重新登录
我的program.cs代码:
//authentication pipline builder.Services.AddHttpContextAccessor(); var initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '); builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(options => { builder.Configuration.Bind("AzureAd", options); options.Events = new OpenIdConnectEvents { //Tap into this event to add a UserID Claim to a new HttpContext identity OnTokenValidated = context => { //This query returns the UserID from the DB by sending the email address in the claim from Azure AD string query = "select dbo.A2F_0013_ReturnUserIDForEmail(@Email) as UserID"; string connectionString = builder.Configuration.GetValue<string>("ConnectionStrings:DBContext"); string signInEmailAddress = context.Principal.FindFirstValue("preferred_username"); using (var connection = new SqlConnection(connectionString)) { var queryResult = connection.QueryFirst(query, new { Email = signInEmailAddress }); var claims = new List<Claim> { new Claim("UserID", queryResult.UserID.ToString()) }; var appIdentity = new ClaimsIdentity(claims); context.Principal.AddIdentity(appIdentity); } return Task.CompletedTask; }, }; }, CookieOptions => { CookieOptions.SlidingExpiration = true; CookieOptions.LoginPath = "/Login/"; CookieOptions.LogoutPath = "/Logout/"; CookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(15); }) .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) .AddInMemoryTokenCaches();
解决方案
1. 修复Cookie过期不触发重新登录的问题
默认情况下,Azure AD的令牌生命周期会覆盖Cookie的过期设置,需要禁用该行为,并确保认证中间件顺序正确:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(options => { builder.Configuration.Bind("AzureAd", options); options.Events = new OpenIdConnectEvents { OnTokenValidated = context => { // 保留你的现有用户ID查询逻辑 return Task.CompletedTask; } }; // 禁用使用令牌生命周期,改用自定义Cookie过期设置 options.UseTokenLifetime = false; }, cookieOptions => { cookieOptions.SlidingExpiration = true; cookieOptions.LoginPath = "/Login/"; cookieOptions.LogoutPath = "/Logout/"; cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(15); // 生产环境建议开启HttpOnly和Secure增强安全性 cookieOptions.HttpOnly = true; cookieOptions.Secure = CookieSecurePolicy.Always; }) .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) .AddInMemoryTokenCaches(); // 确保添加授权服务,并按顺序挂载中间件 builder.Services.AddAuthorization(); // 中间件顺序必须是:CORS → 认证 → 授权 app.UseCors(); // 后续配置CORS策略 app.UseAuthentication(); app.UseAuthorization();
2. 修复清除Cookie无法登出Azure AD的问题
Azure AD的全局会话独立于应用Cookie,需要主动触发Azure AD的登出流程:
- 在
appsettings.json中配置登出回调地址:
"AzureAd": { // 其他配置... "PostLogoutRedirectUri": "https://你的应用域名/Home/Index" }
- 实现Logout控制器:
public async Task<IActionResult> Logout() { // 同时登出Azure AD和应用Cookie会话 await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return RedirectToAction("Index", "Home"); }
3. 解决Cookie失效后的API CORS错误
跨域请求的未授权重定向会被浏览器拦截,需要配置CORS允许凭证,并针对AJAX请求返回401而非重定向:
// 配置CORS策略 builder.Services.AddCors(options => { options.AddPolicy("AllowFrontend", policy => { policy.WithOrigins("https://你的前端域名") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); // 配置Cookie认证事件,处理AJAX请求的未授权情况 builder.Services.ConfigureApplicationCookie(options => { options.Events.OnRedirectToLogin = context => { // 识别AJAX请求,返回401状态码 if (context.Request.Headers["X-Requested-With"] == "XMLHttpRequest") { context.Response.StatusCode = StatusCodes.Status401Unauthorized; } else { context.Response.Redirect(context.RedirectUri); } return Task.CompletedTask; }; }); // 挂载CORS中间件(必须在认证之前) app.UseCors("AllowFrontend"); app.UseAuthentication(); app.UseAuthorization();
内容的提问来源于stack exchange,提问作者Qiuzman
相关产品推荐
相关产品推荐

