Single sign on 身份服务器3+;ASP.NET Core 2.0 MVC应用程序-联合单一注销不包括在结束会话前重定向到ADFS
我的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上,以下是(我相信)相关的配置组件: 其他身份提供程序的配置: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
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);
});
});