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

.NET Framework 4.8集成Azure AD登出重登无限循环问题求助

Azure AD登出后重新登录无限循环问题(.NET Framework 4.8)

我有一个基于.NET Framework 4.8构建的Web应用,已集成Azure AD登录功能。当登出后尝试重新登录时,会进入对Microsoft的调用无限循环,直至出现访问失败错误。已尝试网上各类解决方案,但均未生效。

启动代码

public void Configuration(IAppBuilder app)
{
     string cookieDays = ConfigurationManager.AppSettings["cookieDays"];
     string clientId = ConfigurationManager.AppSettings["ClientId"];
     string authority = ConfigurationManager.AppSettings["Authority"];
     string redirectUri = ConfigurationManager.AppSettings["redirectUri"];
     string logoutRedirectUri = ConfigurationManager.AppSettings["logoutRedirectUri"];
     app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

     app.UseCookieAuthentication(new CookieAuthenticationOptions() {
         AuthenticationType = "Cookies",                                              
         CookieSecure = CookieSecureOption.Always,                       
         ExpireTimeSpan = TimeSpan.FromDays(int.Parse(cookieDays))             
     });            
     app.UseOpenIdConnectAuthentication(
         new OpenIdConnectAuthenticationOptions
         {
             // Sets the client ID, authority, and redirect URI as obtained from Web.config
             ClientId = clientId,                    
             Authority = authority,
             RedirectUri = redirectUri,
             // PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it's using the home page
             PostLogoutRedirectUri = logoutRedirectUri,
             Scope = OpenIdConnectScope.OpenIdProfile,
             // ResponseType is set to request the code id_token, which contains basic information about the signed-in user
             ResponseType = OpenIdConnectResponseType.CodeIdToken,
             // ValidateIssuer set to false to allow personal and work accounts from any organization to sign in to your application
             // To only allow users from a single organization, set ValidateIssuer to true and the 'tenant' setting in Web.config to the tenant name
             // To allow users from only a list of specific organizations, set ValidateIssuer to true and use the ValidIssuers parameter
             TokenValidationParameters = new TokenValidationParameters()
             {                                                
                 ValidateIssuer = false // Simplification (see note below)
             }                   
         }
     );
}

LoginController代码

[Authorize]
public ActionResult Auth()
{
    var userClaims = User.Identity as System.Security.Claims.ClaimsIdentity;
    string email = userClaims?.FindFirst("preferred_username")?.Value;

    using (var entities = new SqlProdDbContext()) 
    {
        Utenti user = entities.Utenti.Where(u => u.Email == email).SingleOrDefault();

        if (user == null) 
        {
            Users temp = new Users();
            temp.LoginErrorMessage = "Utente non valido";
            return View("Index", temp);
        }
    }

    Session["userName"] = userClaims?.FindFirst("name")?.Value;
    Session["UserEmail"] = userClaims?.FindFirst("preferred_username")?.Value;
    Session["Roles"] = "1";           
    Session["name"] = userClaims?.FindFirst("preferred_username")?.Value.Split('@')[0];           

    return RedirectToAction("Index", "Home");
}

public void SignOut()
{
    HttpContext.GetOwinContext().Authentication.SignOut();                        
    HttpContext.Response.AddHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    HttpContext.Response.AddHeader("Pragma", "no-cache");
    HttpContext.Response.AddHeader("Expires", "0");
    HttpContext.Response.Redirect("/");
}

public ActionResult ClearSession()
{
    HttpContext.Session.Clear();
    //Session.Clear();
    Session.Abandon();
    Request.GetOwinContext().Authentication.SignOut();
    Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
    this.HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
    return RedirectToAction("Index");
}     

问题修复方案

1. 统一Cookie认证类型

启动代码中SetDefaultSignInAsAuthenticationType使用默认值CookieAuthenticationDefaults.AuthenticationType,但UseCookieAuthentication的AuthenticationType设为了"Cookies",两者不匹配会导致身份验证流程混乱。修改Cookie认证配置:

app.UseCookieAuthentication(new CookieAuthenticationOptions() {
    AuthenticationType = CookieAuthenticationDefaults.AuthenticationType, // 与默认登录类型一致
    CookieSecure = CookieSecureOption.Always,                       
    ExpireTimeSpan = TimeSpan.FromDays(int.Parse(cookieDays))             
});

2. 完善登出逻辑

当前登出方法未完整触发Azure AD端的会话注销,仅清理本地Cookie会导致云端会话残留,引发循环。修改SignOut方法:

public void SignOut()
{
    // 指定要注销的认证类型:Cookie和OpenIdConnect
    var authTypes = new[] 
    { 
        CookieAuthenticationDefaults.AuthenticationType, 
        OpenIdConnectAuthenticationDefaults.AuthenticationType 
    };
    HttpContext.GetOwinContext().Authentication.SignOut(authTypes);
    
    // 禁用缓存,避免浏览器加载旧会话页面
    HttpContext.Response.AddHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    HttpContext.Response.AddHeader("Pragma", "no-cache");
    HttpContext.Response.AddHeader("Expires", "0");
    
    // 跳转到配置的登出回调地址,而非直接根目录
    var logoutRedirectUri = ConfigurationManager.AppSettings["logoutRedirectUri"];
    HttpContext.Response.Redirect(logoutRedirectUri);
}

3. 添加OpenIdConnect登出通知处理

在OpenIdConnect配置中添加通知,确保登出时传递正确的id_token_hint和回调地址,避免流程异常:

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        // 原有配置...
        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            RedirectToIdentityProvider = n =>
            {
                if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                {
                    // 传递id_token_hint给Azure AD,确保正确注销
                    var idToken = n.OwinContext.Authentication.User.FindFirst("id_token")?.Value;
                    if (!string.IsNullOrEmpty(idToken))
                    {
                        n.ProtocolMessage.IdTokenHint = idToken;
                    }
                    // 明确指定登出回调地址
                    n.ProtocolMessage.PostLogoutRedirectUri = ConfigurationManager.AppSettings["logoutRedirectUri"];
                }
                return Task.FromResult(0);
            }
        }
    }
);

4. 检查Azure AD应用注册配置

确保Web.config中的redirectUri和logoutRedirectUri已在Azure AD应用注册的:

  • 重定向URI(认证->重定向URI)
  • 前端通道注销URI(认证->前端通道注销URI)
    中正确配置,否则会因回调地址不被信任触发流程失败,导致循环。

内容的提问来源于stack exchange,提问作者alessandro vernile

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:17:11