首页 > 解决方案 > 为什么 OIDC 登录在 Edge 中中断,但在 FireFox 中没有?

问题描述

我在一个网站(.NET Framework 4.6.1)上工作,我们实现了 OIDC 身份验证(IdentityServer4)。实现是非常基本的,没有什么特别的,只是一些代码挑战和令牌验证。我们对其进行了测试,它在 Edge 和 FireFox 上运行得非常好。

然后我们被要求为 MFA 实现“acr_values”参数。在身份验证配置中,特别是在内部RedirectToIdentityProvider(属于Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications),我们通过以下方式添加指定的“acr_values”参数(该值本身在配置文件中设置,类似于“xyz:asd:wtf:qwe”) :

n.ProtocolMessage.AcrValues = authCfg.AcrValues

在非常相似的设置中(我的意思是几乎相同),它可以正常工作。对于我的设置,它仅适用于 Firefox。在 Edge 中尝试时,我们得到AuthenticationFailed(也是 a Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications)并出现以下错误:

2021-05-26 13:00:08.0633 错误 MT.Translate.Startup OIDC-Notification: AuthenticationFailed:

2021-05-26 13:00:08.0633 错误 MT.Translate.Startup 值不能为空。参数名称:s

2021-05-26 13:00:08.0633 错误 MT.Translate.Startup -TargetSite--------------------------------------------

2021-05-26 13:00:08.0633 错误 MT.Translate.Startup Byte[] FromBase64String(System.String)

2021-05-26 13:00:08.0633 错误 MT.Translate.Startup -Source-------------------------------- ---

2021-05-26 13:00:08.0633 错误 MT.Translate.Startup mscorlib

在开发环境中,行为有点不同。我们没有得到AuthenticationFailed,因为在验证了登录信息之后,IdentityServer 的重定向什么也不做,而是将我们返回到相同的登录屏幕。

总结一下,没有“acr:values”,MFA 无法正常工作,但在 Edge 和 Firefox 中都可以正常工作。在实施ig“acr_values”之后,Firefox 正在使用 MFA,但不在 Edge 中。所以我们回滚到以前的版本,我们没有“acr_values”,现在 MFA 也可以与 Edge 和 Firefox 一起使用。

该错误对我没有任何意义。没有称为“s”的参数,至少我在身份验证的上下文中从未听说过它。如果没有必要的代码,它就可以工作,这一事实对我来说没有任何意义。此外,它如何在 Firefox 上运行而不是在 Edge 上运行?

奖励目标:仅在 Edge 中没有出现 png。它没有被触及,并且在所有其他浏览器中都会显示。如何以及为什么是我的问题。

感谢您阅读我的帖子,我期待了解正在发生的事情。

一些代码片段:

oicdAuthOpt.Notifications = new OpenIdConnectAuthenticationNotifications
            {
                RedirectToIdentityProvider = n =>
                {
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication && AppSettingsKey.AuthCodeChallangeEnabled.Enabled)
                    {
                        // generate code verifier and code challenge
                        var codeVerifier = CryptoRandom.CreateUniqueId(32);

                        string codeChallenge;
                        using (var sha256 = SHA256.Create())
                        {
                            var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                            codeChallenge = Base64UrlEncoder.Encode(challengeBytes);
                        }

                        // set code_challenge parameter on authorization request
                        n.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge);
                        n.ProtocolMessage.Parameters.Add("code_challenge_method", "S256");

                        if (AppSettingsKey.MultiFactorAuthEnabled.Enabled)
                            n.ProtocolMessage.AcrValues = authCfg.AcrValues ?? n.ProtocolMessage.AcrValues;

                        // remember code verifier in cookie (adapted from OWIN nonce cookie)
                        // see: https://github.com/scottbrady91/Blog-Example-Classes/blob/master/AspNetFrameworkPkce/ScottBrady91.BlogExampleCode.AspNetPkce/Startup.cs#L85
                        RememberCodeVerifier(n, codeVerifier);
                    }
                    logger.Debug("OIDC-Notification: RedirectToIdentityProvider Called");

                    //if signing out, add the id_token_hint
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                    {
                        logger.Debug("  RequestType=" + OpenIdConnectRequestType.Logout);
                        var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                        if (idTokenHint != null)
                        {
                            logger.Debug("  IdTokenHint got from n.OwinContext.Authentication.User");
                            n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                        }
                        logger.Debug("  IdTokenHint=" + n?.ProtocolMessage?.IdTokenHint);
                        
                    }
                    return Task.CompletedTask;
                },

IndentityServer 的代码在他们的 github(快速入门)上。对于授权中间件,我们定制了System.Web.Mvc.AuthorizeAttribute.

public override void OnAuthorization(AuthorizationContext filterContext)
        {
            try
            {
                if (AppSettingsKey.LoginEnabled.Enabled && AppSettingsKey.OpenIdConnectSSOEnabled.Enabled)
                {
                    var cookie = HttpContext.Current.Request.Cookies["oidc.default"];
                    if (cookie == null)
                    {
                        logger.Debug("oidc.default is null -> HandleUnauthorizedRequest");
                        base.HandleUnauthorizedRequest(filterContext);
                    }
                    else
                    {

                        if (CookieKeyStore.Instance.CheckIfContains(cookie.Value))
                        {
                            if (!CookieKeyStore.Instance.isExpired(cookie.Value))
                            {
                                logger.Debug("oidc.default is not expired:" + cookie.Value + " -> OnAuthorization");
                                //requires oidc.default and ASP.NET_SessionID cookies
                                base.OnAuthorization(filterContext);
                            }
                            else
                            {
                                logger.Debug("oidc.default is expired:" + cookie.Value + " -> HandleUnauthorizedRequest");
                                base.HandleUnauthorizedRequest(filterContext);
                            }
                        }
                        else
                        {
                            logger.Debug("insert oidc.default into the KeyStore:" + cookie.Value + " -> OnAuthorization");
                            CookieKeyStore.Instance.HandleCookies(cookie);
                            base.OnAuthorization(filterContext);
                        }
                    }

                }
                else
                    base.OnAuthorization(filterContext);

            }
            catch (Exception e)
            {
                logger.Error(e, "Exception while overriding the OnAuthorization method.");
            }
        }

“oidc.default”是我们配置到 OIDC 中的自定义 cookie。

app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            CookieName = "oidc.default",
            CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager(),
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnResponseSignOut = context =>
                {
                    CookieKeyStore.Instance.Clear(context.Request.Cookies["oidc.default"]);
                }
            }
        });

标签: firefoxmicrosoft-edgeopenid-connect.net-framework-version

解决方案


推荐阅读