Asp.net mvc Azure应用程序服务上的瞬时无限登录循环-OpenIDConnect Auth with Azure AD

Asp.net mvc Azure应用程序服务上的瞬时无限登录循环-OpenIDConnect Auth with Azure AD,asp.net-mvc,azure-active-directory,openid-connect,azure-app-service-envrmnt,Asp.net Mvc,Azure Active Directory,Openid Connect,Azure App Service Envrmnt,背景 因此,我们有一个应用程序服务,它使用OpenIdConnect从另一个租约中的Azure AD进行身份验证 登录可以在IIS的开发实例上工作,也可以在我们的测试应用程序服务上工作。我们在测试中看到了这个问题,它消失了,在项目的整个测试阶段都没有出现 现在我们已经部署到生产环境中,我们再次看到了这个问题 问题 我们看到的是,在一段时间内,一切都会正常运行,然后几个小时后,问题会再次出现 我们有一个修复恢复服务的方法,即在azure控制面板中启用并禁用应用程序服务身份验证。反之亦然——先禁用然

背景

因此,我们有一个应用程序服务,它使用OpenIdConnect从另一个租约中的Azure AD进行身份验证

登录可以在IIS的开发实例上工作,也可以在我们的测试应用程序服务上工作。我们在测试中看到了这个问题,它消失了,在项目的整个测试阶段都没有出现

现在我们已经部署到生产环境中,我们再次看到了这个问题

问题

我们看到的是,在一段时间内,一切都会正常运行,然后几个小时后,问题会再次出现

我们有一个修复恢复服务的方法,即在azure控制面板中启用并禁用应用程序服务身份验证。反之亦然——先禁用然后启用将恢复服务

代码

问题


所以,无论启用和禁用应用程序服务认证做了什么,这显然是暂时解决问题。所以我认为这是一个与cookie相关的问题,因为这是在会话之间传输状态的唯一方法。这里到底有什么问题?我需要采取什么步骤来诊断和解决问题?

到目前为止,似乎是Katana中的一个已知错误导致Katana cookie manager和ASP.NET cookie manager发生冲突并覆盖彼此的cookie

以下是一些您可以参考的疑难解答:

1.设置 app.UseCookieAuthenticationnew CookieAuthenticationOptions{CookieSecure==CookieSecureOption.Always}。这意味着cookie可能会随您的身份验证一起泄漏

2.在Microsoft.Owin.Host.SystemWeb Nuget包中的UseCookieAuthentication中添加SystemWebCookieManager。请参考这个

3。。有人注意到,如果Cookie字符超过浏览器限制>4096,这是一个问题。所以为了克服这个问题,在设置cookie时,每个cookie大约有4000个字符,需要时将所有cookie组合在一起以获得原始值

有关如何将Microsoft登录添加到ASP.NET web应用程序的详细信息,请参阅此

更新:


使用install Kentor.OwinCookieSaver nuget包修复,并添加app.usekentorowicookiesaver;在app.UseCookieAuthenticationnew CookieAuthenticationOptions之前

我昨晚安装了Owincokiesaver,它似乎可以正常工作。所以我们都认为这是一个与cookie有关的问题,尽管你比我更正确。Joey,如果你想用Kentor.OwinCookieSaver补丁编辑,我会接受这个回复,因为我就是这么做的。
public void ConfigureAuth(IAppBuilder app)
        {
            //Azure AD Configuration
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());


            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    //sets client ID, authority, and RedirectUri as obtained from web config
                    ClientId = clientId,
                    ClientSecret = appKey,
                    Authority = authority,
                    RedirectUri = redirectUrl,

                    CallbackPath = new PathString("/"), //use this line for production and test


                    //page that users are redirected to on logout
                    PostLogoutRedirectUri = redirectUrl,

                    //scope - the claims that the app will make
                    Scope = OpenIdConnectScope.OpenIdProfile,
                    ResponseType = OpenIdConnectResponseType.CodeIdToken,

                    //setup multi-tennant support here, or set ValidateIssuer = true to config for single tennancy
                    TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = true,
                        //SaveSigninToken = true
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = OnAuthenticationFailed,
                        AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    }
                }
                );
        }

        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
        {
            var code = context.Code;
            ClientCredential cred = new ClientCredential(clientId, appKey);
            string userObjectId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            //this token cache is stateful, we're going to populate it here, but we'll store it elsewhere in-case the user ends up accessing a different instance
            AuthenticationContext authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));

            // If you create the redirectUri this way, it will contain a trailing slash.  
            // Make sure you've registered the same exact Uri in the Azure Portal (including the slash).
            Uri uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
            AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, uri, cred, "https://graph.windows.net");

            //populate the persistent token cache
            testdb2Entities5 db = new testdb2Entities5();
            PersistentTokenCache tc = await db.PersistentTokenCaches.FindAsync(userObjectId);
            //if null, populate a new item
            if (tc == null)
            {
                tc = new PersistentTokenCache();
                tc.object_id = userObjectId;
                tc.token = code;
                db.PersistentTokenCaches.Add(tc);
                await db.SaveChangesAsync();

            }
            else
            {
                tc.token = code;
                await db.SaveChangesAsync();
            }

        }

        //authentication failed notifications
        private Task OnAuthenticationFailed(AuthenticationFailedNotification<Microsoft.IdentityModel.Protocols
                                                                            .OpenIdConnect.OpenIdConnectMessage,
                                                                            OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("/?errormessage=" + context.Exception.Message);
            return Task.FromResult(0);
        }