You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

清除浏览器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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:01:12