Single sign on 身份服务器3+;ASP.NET Core 2.0 MVC应用程序-联合单一注销不包括在结束会话前重定向到ADFS

Single sign on 身份服务器3+;ASP.NET Core 2.0 MVC应用程序-联合单一注销不包括在结束会话前重定向到ADFS,single-sign-on,adfs,identityserver3,Single Sign On,Adfs,Identityserver3,我的web应用程序是Identity Server 3 STS的客户端,它与外部IdP的ADF联合。登录非常有效。从STS注销即可。但在结束IdSrv3会话并最终重定向到应用程序之前,我一直无法让IdSrv3重定向到ADFS进行注销 如果我理解正确,我应该能够在注销后将ADFS发回RP(IdSrv3),此时IdSrv3 阅读文档: 以及围绕联邦单一注销主题的GitHub问题选集 通过IdSrv3进行跟踪,我从未看到有人试图重定向到ADFS进行注销,所以我假设我缺少这里的配置 曾经,我运行的是I

我的web应用程序是Identity Server 3 STS的客户端,它与外部IdP的ADF联合。登录非常有效。从STS注销即可。但在结束IdSrv3会话并最终重定向到应用程序之前,我一直无法让IdSrv3重定向到ADFS进行注销

如果我理解正确,我应该能够在注销后将ADFS发回RP(IdSrv3),此时IdSrv3

阅读文档:

以及围绕联邦单一注销主题的GitHub问题选集

通过IdSrv3进行跟踪,我从未看到有人试图重定向到ADFS进行注销,所以我假设我缺少这里的配置

曾经,我运行的是IdSrv3,但我的客户端应用程序是ASP.NET Core 2.0,因此许多示例与最新的Microsoft identity客户端中间件不完全一致

在IdSrv3上,以下是(我相信)相关的配置组件:

其他身份提供程序的配置:

        var wsFed = new WsFederationAuthenticationOptions
        {
            Wtrealm = ConfigurationManager.AppSettings["Wtrealm"],
            MetadataAddress = metaDataAddress,
            AuthenticationType = "ADFS",
            Caption = "ACME ADFS",
            SignInAsAuthenticationType = signInAsType
        };
IdSrv3中间件:

coreApp.UseIdentityServer(
                    new IdentityServerOptions
                    {

                        SiteName = "eFactoryPro Identity Server",
                        SigningCertificate = Cert.Load(),
                        Factory = factory,
                        RequireSsl = true,

                        AuthenticationOptions = new AuthenticationOptions
                        {
                            IdentityProviders = ConfigureAdditionalIdentityProviders,
                            EnablePostSignOutAutoRedirect = true,
                            EnableSignOutPrompt = false,
                            EnableAutoCallbackForFederatedSignout = true
                        },
                        LoggingOptions = new LoggingOptions
                        {
                            EnableHttpLogging = true,
                            EnableKatanaLogging = true,
                            //EnableWebApiDiagnostics = true,
                            //WebApiDiagnosticsIsVerbose = true
                        }
                    });
                coreApp.Map("/signoutcallback", cleanup =>
                {
                    cleanup.Run(async ctx =>
                    {
                        var state = ctx.Request.Cookies["state"];
                        await ctx.Environment.RenderLoggedOutViewAsync(state);
                    });
                });
            });
现在,对于客户端,ASP.NET Core 2.0 MVC应用程序:

更新:请参阅接受的答案-关于重定向到外部IdP(ADFS),应在IdSrv3端处理重定向到IdP以注销的问题

从文档中,我应该将“注销消息id”传递到“状态”cookie中。但是,这种扩展方法在ASP.NET Core 2.0中不起作用,因为我们不再真正有权访问OwinContext

var signOutMessageId=n.OwinContext.Environment.GetSignOutMessageId()

我甚至尝试实例化一个新的OwinContext(n.HttpContext)来获取环境字典-但是,“GetSignOutMessageId()”获取的值有一个键“id”,我在Owin变量中找不到该键

看起来这个cookie只是在所有重定向中保持状态所必需的,这样在我的客户端应用程序的PostLogoutUri被命中(当前设置为“”)后,消息id就可以用来完成会话清理

我还不清楚“EnableAutoCallbackForFederatedSignout=true”设置在IdSrv3配置中扮演什么角色

从下面的描述和代码可以看出,这使我不必在ADFS注销时设置“WReply”参数: 我预计ADFS将重定向到: “”如果此设置为“true”,则自动执行


如果有人能提供任何指导,我将不胜感激。

事实证明,我将IdSrv3中描述由外部Idp发起的联合单点注销的一些概念与我的用例相融合,而不是由IdSrv3客户端应用程序发起的注销,级联“向上”到外部Idp

这个问题的根本原因是我的UserService实现。在那里,我重写了“AuthenticateExternalAsync()”方法,但没有在AuthenticateResult对象中指定外部身份提供程序

以下是正确的实现:

        public override Task AuthenticateExternalAsync(ExternalAuthenticationContext context)
        {

         ...

                context.AuthenticateResult = new AuthenticateResult(
                    user.Id, 
                    user.UserName, 
                    new List<Claim>(), 
                    context.ExternalIdentity.Provider);

            return Task.FromResult(0);
        }
最后,我的/外部签出清理实现:

 Notifications = new WsFederationAuthenticationNotifications()
            {
                RedirectToIdentityProvider = n =>
                {

                    if (n.ProtocolMessage.IsSignOutMessage)
                    {
                        var signOutMessageId = n.OwinContext.Environment.GetSignOutMessageId();
                        if (signOutMessageId != null)
                        {
                            n.OwinContext.Response.Cookies.Append("state", signOutMessageId);
                        }

                        var cleanUpUri =
                            $@"{n.Request.Scheme}://{n.Request.Host}{n.Request.PathBase}/external-signout-cleanup";

                        n.ProtocolMessage.Wreply = cleanUpUri;
                    }

                    return Task.FromResult(0);
                }
            }
                coreApp.Map("/external-signout-cleanup", cleanup =>
                {
                    cleanup.Run(async ctx =>
                    {
                        var state = ctx.Request.Cookies["state"];
                        await ctx.Environment.RenderLoggedOutViewAsync(state);
                    });
                });

事实证明,我将IdSrv3中描述由外部Idp发起的联邦单点注销的一些概念与我的用例(由IdSrv3客户端应用程序发起的注销)“向上”级联到外部Idp)混为一谈

这个问题的根本原因是我的UserService实现。在那里,我重写了“AuthenticateExternalAsync()”方法,但没有在AuthenticateResult对象中指定外部身份提供程序

以下是正确的实现:

        public override Task AuthenticateExternalAsync(ExternalAuthenticationContext context)
        {

         ...

                context.AuthenticateResult = new AuthenticateResult(
                    user.Id, 
                    user.UserName, 
                    new List<Claim>(), 
                    context.ExternalIdentity.Provider);

            return Task.FromResult(0);
        }
最后,我的/外部签出清理实现:

 Notifications = new WsFederationAuthenticationNotifications()
            {
                RedirectToIdentityProvider = n =>
                {

                    if (n.ProtocolMessage.IsSignOutMessage)
                    {
                        var signOutMessageId = n.OwinContext.Environment.GetSignOutMessageId();
                        if (signOutMessageId != null)
                        {
                            n.OwinContext.Response.Cookies.Append("state", signOutMessageId);
                        }

                        var cleanUpUri =
                            $@"{n.Request.Scheme}://{n.Request.Host}{n.Request.PathBase}/external-signout-cleanup";

                        n.ProtocolMessage.Wreply = cleanUpUri;
                    }

                    return Task.FromResult(0);
                }
            }
                coreApp.Map("/external-signout-cleanup", cleanup =>
                {
                    cleanup.Run(async ctx =>
                    {
                        var state = ctx.Request.Cookies["state"];
                        await ctx.Environment.RenderLoggedOutViewAsync(state);
                    });
                });