IdentityServer4多个WSFederation-providers导致异常

Com*_*eak 2 c# ws-federation .net-core asp.net-core identityserver4

我被告知我将在这里描述的问题不是IdentityServer中的错误,所以我可能做错了什么:

此代码在使用EFCoreQuickStart项目中使用单个WSFederation实例作为标识提供程序工作.

注册提供者:

services.AddAuthentication()
            .AddWsFederation("WsFederation", options =>
            {
                options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                options.Wtrealm = realm;
                options.MetadataAddress = metadata;
                options.Events.OnTicketReceived += OnTicketReceived;
            })
Run Code Online (Sandbox Code Playgroud)

OnTicketReceived-事件处理程序:

/// <summary>
/// Transform the UPN-claim to the sub-claim to be compatible with IdentityServer4
/// </summary>
private async Task OnTicketReceived(TicketReceivedContext ticketReceivedContext)
{
     var identity = ticketReceivedContext.Principal.Identities.First();
     identity.AddClaim(new Claim("sub", ticketReceivedContext.Principal.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")));

}
Run Code Online (Sandbox Code Playgroud)

一旦我添加第二个提供程序,我将在尝试使用第二个提供程序时遇到异常,因为添加的第一个提供程序接收请求并在收到请求后立即抛出异常:

services.AddAuthentication()
.AddWsFederation("WsFederation_LocalHost", "WsFederation_LocalHost", options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    options.Wtrealm = "urn:aspnetcorerp";
                    options.MetadataAddress = "http://localhost:5000/wsfederation";
                    options.Events.OnTicketReceived += OnTicketReceived;
                    options.RequireHttpsMetadata = false;
                })
                .AddWsFederation("WsFederation_SVN", "WsFederation_SVN", options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    options.Wtrealm = realm;
                    options.MetadataAddress = metadata;
                    options.Events.OnTicketReceived += OnTicketReceived;
                    options.Events.OnSecurityTokenReceived += OnSecurityTokenReceived;
                })
Run Code Online (Sandbox Code Playgroud)

我得到的例外是 - 如果我通过允许未经请求的登录来修复它,则会发生其他异常,因为它仍然会尝试使用错误的提供程序:

System.Exception:不允许未经请求的登录.在Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.d__12.MoveNext()

我发现在IdentityServer4中引发它的地方:

public async Task<bool> HandleRequestAsync()
    {
var result = await _inner.HandleRequestAsync();
Run Code Online (Sandbox Code Playgroud)

如果我更改上面的代码以捕获异常,我可以解决这个问题,因为它将在之后传递正确的提供程序并且登录成功:

var result = false;
try
{
   result = await _inner.HandleRequestAsync();
}
catch (Exception) {}
Run Code Online (Sandbox Code Playgroud)

我不满意必须分叉IdentityServer4来解决这个问题,所以我要求一个解决方案而不改变IdentityServer的代码.我可以介入并更改内容的地方是我的WSFederation端点的配置,在启动ExternalLogin之前 AccountController 的回调中.

AccountController中的回调:

    [HttpGet]
    public async Task<IActionResult> ExternalLoginCallback()
    {
        // read external identity from the temporary cookie - I don't know how I could change which AuthenticationMiddleware gets called
        var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
Run Code Online (Sandbox Code Playgroud)

我应该开始的任何提示都非常感谢.

Com*_*eak 5

知道了 - 解决方案是为不同的提供者设置不同的CallbackPath:

services.AddAuthentication()
                .AddWsFederation("WsFederation_LocalHost", "WsFederation_LocalHost", options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    options.Wtrealm = "urn:aspnetcorerp";
                    options.MetadataAddress = "http://localhost:5000/wsfederation";
                    options.Events.OnTicketReceived += OnWsFedTicketReceived;
                    options.RequireHttpsMetadata = false;
                    options.CallbackPath = "/signin-wsfed-localhost";
                })
                .AddWsFederation("WsFederation_SVN", "WsFederation_SVN", options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    options.Wtrealm = realm;
                    options.MetadataAddress = metadata;
                    options.Events.OnTicketReceived += OnWsFedTicketReceived;
                    options.CallbackPath = "/signin-wsfed-svn";
                })
Run Code Online (Sandbox Code Playgroud)