第一次成功登录 MVC .NET 5 OWIN ADAL OpenIDConnect 后,第二次登录导致无限重定向循环 [英] Second sign-in causes infinite redirect loop after the first successful login MVC .NET 5 OWIN ADAL OpenIDConnect

查看:11
本文介绍了第一次成功登录 MVC .NET 5 OWIN ADAL OpenIDConnect 后,第二次登录导致无限重定向循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第一次发帖所以要温柔!:)

first post so be gentle! :)

我正在为 Office 365 开发 MVC .NET 5 Web 应用程序,并且正在使用 OpenIDConnect 框架.我已经设置了 OWIN (3) 和 ADAL(2) 以及我的 Azure AD 应用程序.没有用户操作登录,主控制器附加了 [Authorize] 属性,强制立即登录重定向到 Azure AD.我没有在我的任何授权属性中使用角色.

I'm developing an MVC .NET 5 web app for Office 365 and am using the OpenIDConnect framework. I have set up OWIN (3) and ADAL(2) and my Azure AD Application. There is no user actioned login, the home controller has an [Authorize] attribute attached, forcing the immediate login redirect to Azure AD. I am not using roles in any of my Authorize attributes.

问题:我可以成功登录我的应用程序 - 一次!第一次登录后,我关闭浏览器(或在另一台机器上打开一个新浏览器),然后再次点击该应用程序.它会将我重定向到我登录的 Azure AD 登录屏幕,然后它会不断在应用程序和 Azure 之间重定向,直到我收到臭名昭著的 400 标头.查看cookie商店,我发现它充满了随机数.我检查了缓存(Vittorio 的 EFADALCache 配方,虽然我在发现这个问题时使用的是 TokenCache.DefaultShared)并且它有数百行缓存数据(只有一行生成成功登录).

The Problem: I can log in to my applications successfully - ONCE! After the first login, I close the browser (or open a new browser on a different machine) and I hit the app again. It redirects me to the Azure AD login screen which I sign into and then it continuously redirects between the app and Azure until I get the infamous 400 headers to long issue. Looking into the cookie store, I find that it's full of nonces. I check the cache (Vittorio's EFADALCache recipe, although I was using the TokenCache.DefaultShared when this problem was discovered) and it has hundreds of rows of cache data (Only one row generated with a successful sign in).

我可以通过输出窗口看到重定向发生,每次往返都会生成一个新的访问和刷新令牌:

I can see as the redirects occur via the output window that a new access and refresh token is being generated each round trip:

Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache
Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52:  - TokenCache: Deserialized 1 items to token cache.
iisexpress.exe Information: 0 : 31/07/2015 12:31:52:  - TokenCache: Deserialized 1 items to token cache.
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache...
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache...
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache
Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenHandlerBase: === Token Acquisition finished successfully. An access token was retuned:
    Access Token Hash: PN5HoBHPlhhHIf1lxZhEWb4B4Hli69UKgcle0w7ssvo=
    Refresh Token Hash: 3xmypXCO6MIMS9qUV+37uPD4kPip9WDH6Ex29GdWL88=
    Expiration Time: 31/07/2015 13:31:51 +00:00
    User Hash: GAWUtY8c4EKcJnsHrO6NOzwcQDMW64z5BNOvVIl1vAI=

当问题发生时,我的 OpenIdConnectAuthenticationOptions 中的 AuthorizationCodeReceived 通知被命中,所以我知道 Azure 认为登录成功(否则重定向回应用程序不会发生):

The AuthorizationCodeReceived notification in my OpenIdConnectAuthenticationOptions is being hit when the problem is happening, so I know that Azure thinks the login was successful (or else the redirect back to the app wouldn't occur):

    private static void PrepO365Auth(IAppBuilder app)
    {

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        //Configure OpenIDConnect, register callbacks for OpenIDConnect Notifications
        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {

                ClientId = ConfigHelper.ClientId,
                Authority = authority,
                PostLogoutRedirectUri = "https://localhost:44300/Account/SignedOut",
                RedirectUri = "https://localhost:44300/",
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = (context) =>
                    {
                        ClientCredential credential = new ClientCredential(ConfigHelper.ClientId, ConfigHelper.AppKey);
                        string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

                        AuthenticationContext authContext = new AuthenticationContext(authority, new EFADALTokenCache(signedInUserID)); // TokenCache.DefaultShared Probably need a persistent token cache to handle app restarts etc
                        AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                            context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigHelper.GraphResourceId);

                        return Task.FromResult(0);
                    },

                    AuthenticationFailed = context =>
                    {
                        context.HandleResponse();
                        context.Response.Redirect("/Error/ShowError?signIn=true&errorMessage=" + context.Exception.Message);
                        return Task.FromResult(0);
                    }
                }
            });
    }
}

我已经用我自己的 Auth 属性替换了(在发现问题后)Authorized 属性,继承自 AuthorizeAttribute,这样我就可以尝试进入 Authorize 代码,看看发生了什么.我从 MVC 5 源代码的第 5 版构建了一个 PDB 文件,但所有发生的事情就是它跳回到我自己的代码中 :( 话虽如此,我已经覆盖了我能找到的 filterContext.HttpContext.User.Identity.IsAuthenticated 为 false,这是有道理的,因为这会导致重定向回 Azure 登录.

I have replaced (after discovering the problem) the Authorized attribute with my own Auth attribute, inheriting from AuthorizeAttribute, just so I could try and step into the Authorize code and see what's happening. I built a PDB file from the version 5 version of MVC 5's source code, but all that happens is that it jumps back into my own code :( That being said, I've overridden what I could and have found that filterContext.HttpContext.User.Identity.IsAuthenticated is false, which makes sense, as that would cause the redirect back to Azure sign in.

所以,我知道:

  • Azure 正在接受我的登录并返回相关令牌
  • 在第二次登录时,在 OnAuthorization 之前,filterContext.HttpContext.User.Identity.IsAuthenticated 返回 false
  • 我的 Azure 应用程序配置很好,否则根本无法进行身份验证

我认为:

  • MVC 标识设置中存在错误.Azure 工作正常,否则根本无法进行身份验证.
  • 这不是 cookie 问题,因为如果您在另一台机器上进行第二次登录,就会出现问题

很抱歉,这有点啰嗦,但是这些无限重定向问题太多了,我需要解释为什么我的情况有所不同!

I'm sorry this is a bit long winded, but there are so many of these infinite redirect issues out there, I needed to explain why my situation was different!

我正在寻找的(如果不是答案!)是朝着正确方向推动我如何进一步调试.

What I'm looking for (if not an answer!) is a push in the right direction as to how I can debug further.

感谢您提供的任何帮助!

Appreciate any help you can give!

安迪

推荐答案

已经为任何感兴趣的人找到了答案.这是 Katana 中的一个已知错误,即 Katana cookie 管理器和 ASP .NET cookie 管理器发生冲突并覆盖彼此的 cookie.此处的完整详细信息和解决方法:

Have found the answer for anyone interested. It's a known bug in Katana where the Katana cookie manager and the ASP .NET cookie manager clash and overwrite each other's cookies. Full details and workaround here:

http://katanaproject.codeplex.com/wikipage?title=System.Web%20response%20cookie%20integration%20issues&referringTitle=文档

下面显示的 SystemWebCookieManager 现在可以在 Microsoft.Owin.Host 中找到.SystemWeb Nuget 包.

The SystemWebCookieManager shown below can now be found in the Microsoft.Owin.Host.SystemWeb Nuget package.

添加 CodePlex 终止时的代码:

Adding the code for when CodePlex dies:

//stick this in public void ConfigureAuth(IAppBuilder app)
  app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                // ...
                CookieManager = new SystemWebCookieManager()
            });

//And create this class elsewhere:
public class SystemWebCookieManager : ICookieManager
    {
        public string GetRequestCookie(IOwinContext context, string key)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            var cookie = webContext.Request.Cookies[key];
            return cookie == null ? null : cookie.Value;
        }

        public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

            bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
            bool pathHasValue = !string.IsNullOrEmpty(options.Path);
            bool expiresHasValue = options.Expires.HasValue;

            var cookie = new HttpCookie(key, value);
            if (domainHasValue)
            {
                cookie.Domain = options.Domain;
            }
            if (pathHasValue)
            {
                cookie.Path = options.Path;
            }
            if (expiresHasValue)
            {
                cookie.Expires = options.Expires.Value;
            }
            if (options.Secure)
            {
                cookie.Secure = true;
            }
            if (options.HttpOnly)
            {
                cookie.HttpOnly = true;
            }

            webContext.Response.AppendCookie(cookie);
        }

        public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            AppendResponseCookie(
                context,
                key,
                string.Empty,
                new CookieOptions
                {
                    Path = options.Path,
                    Domain = options.Domain,
                    Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
                });
        }
    }

我也做了一个要点:https://gist.github.com/irwinwilliams/823f43ef19a405e

这篇关于第一次成功登录 MVC .NET 5 OWIN ADAL OpenIDConnect 后,第二次登录导致无限重定向循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆