IdentityServer3,Azure Active Directory 外部提供商,消息='返回的操作 'System.Web.Http.Results.Unauthorized''

IdentityServer3, Azure Active Directory External Provider, Message='Action returned 'System.Web.Http.Results.Unauthorized''

我发现 IdentityServer3 和外部提供商有奇怪的行为。我希望有人能够指出我遗漏的一些明显的东西。

摘要

第一个外部登录请求设置浏览器等待请求返回并导致以下错误仅通过日志记录可见。如果我在浏览器中取消请求并立即再次单击该按钮,它将按预期工作,浏览器将发送到外部登录屏幕。


配置

我已经根据一些参考资料和文档以及我可以确定的内容配置了 IDSrv3,以利用 Azure Active Directory。

 var wsFedOptions = new WsFederationPluginOptions(options);
    wsFedOptions.Factory.Register(new Registration<IEnumerable<RelyingParty>>(RelyingParties.Get()));
    wsFedOptions.Factory.RelyingPartyService = new Registration<IRelyingPartyService>(typeof(InMemoryRelyingPartyService));
    app.UseWsFederationPlugin(wsFedOptions);



 var aad = new OpenIdConnectAuthenticationOptions
            {
                AuthenticationType = "AzureAd",
                Caption = "Azure AD",
                SignInAsAuthenticationType = signInAsType,
                PostLogoutRedirectUri = Settings.LogoutRedirect,
                Authority = Settings.AADAuthority,
                ClientId = Settings.AADClientId,
                RedirectUri = Settings.AADRedirectUrl
            };

            app.UseOpenIdConnectAuthentication(aad);

在登录视图中,我看到了上面标题中的外部登录按钮 (Azure AD),正如预期的那样。第一次单击此按钮时,浏览器只是等待主机...

在日志中我发现了以下错误。


iisexpress.exe Information: 0 : 2017-04-05 08:28:09.708 -05:00 [Information] External login requested for provider: "AzureAd"
iisexpress.exe Information: 0 : 2017-04-05 08:28:09.714 -05:00 [Information] Triggering challenge for external identity provider
LibLog Information: 0 : [2017-04-05T13:28:09.7176576Z] Level=Info, Kind=End, Category='System.Web.Http.Action', Id=800000ad-0002-fb00-b63f-84710c7967bb, Message='Action returned 'System.Web.Http.Results.UnauthorizedResult'', Operation=ReflectedHttpActionDescriptor.ExecuteAsync
LibLog Information: 0 : [2017-04-05T13:28:09.7206611Z] Level=Info, Kind=End, Category='System.Web.Http.Action', Id=800000ad-0002-fb00-b63f-84710c7967bb, Operation=ApiControllerActionInvoker.InvokeActionAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7216630Z] Level=Info, Kind=Begin, Category='System.Web.Http.Filters', Id=800000ad-0002-fb00-b63f-84710c7967bb, Message='Action filter for 'LoginExternal(String signin, String provider)'', Operation=NoCacheAttribute.OnActionExecutedAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7226640Z] Level=Info, Kind=End, Category='System.Web.Http.Filters', Id=800000ad-0002-fb00-b63f-84710c7967bb, Operation=NoCacheAttribute.OnActionExecutedAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7226640Z] Level=Info, Kind=Begin, Category='System.Web.Http.Filters', Id=800000ad-0002-fb00-b63f-84710c7967bb, Message='Action filter for 'LoginExternal(String signin, String provider)'', Operation=SecurityHeadersAttribute.OnActionExecutedAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7236655Z] Level=Info, Kind=End, Category='System.Web.Http.Filters', Id=800000ad-0002-fb00-b63f-84710c7967bb, Operation=SecurityHeadersAttribute.OnActionExecutedAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7246669Z] Level=Info, Kind=End, Category='System.Web.Http.Controllers', Id=800000ad-0002-fb00-b63f-84710c7967bb, Operation=AuthenticationController.ExecuteAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7251836Z] Level=Info, Kind=End, Category='System.Web.Http.MessageHandlers', Id=800000ad-0002-fb00-b63f-84710c7967bb, Operation=PassiveAuthenticationMessageHandler.SendAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7261856Z] Level=Info, Kind=End, Category='System.Web.Http.MessageHandlers', Id=800000ad-0002-fb00-b63f-84710c7967bb, Operation=DependencyScopeHandler.SendAsync, Status=401 (Unauthorized)
LibLog Information: 0 : [2017-04-05T13:28:09.7271879Z] Sending response, Status=401 (Unauthorized), Method=GET, Url=https://localhost:44396/identity/external?provider=AzureAd&signin=2d92dd18a6106c9b029eb8742d4117a1, Id=800000ad-0002-fb00-b63f-84710c7967bb, Message='Content-type='none', content-length=unknown'

浏览器将无限期地继续等待本地主机。 如果我停止请求并立即再次单击按钮,一切都会按预期进行。

基于 OpenIdConnectAuthenticationOptions 代码似乎是正确的。我还使用下面的代码通过 Azure AD 帐户登录 IdentityServer3,它对我来说效果很好:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Trace()
            .CreateLogger();

        var users = new List<InMemoryUser>()
        {
            new InMemoryUser
            {
                Username="Jack", Password="Jack",
                Claims= new List<Claim>
                {
                    new Claim("name","Jack"),
                    new Claim("email","Jack@consoto.com"),
                    new Claim("role","Admin"),
                }
            }
        };

        var clients = new Client[]
        {
            new Client
            {
                ClientId="mvc",
                ClientName="MVC Demo Client",
                Flow=Flows.Implicit,
                RedirectUris=new List<string>
                {
                    "http://localhost:9000",
                    "http://localhost:1409/"
                },
                AllowedScopes=new List<string>
                {
                    "openid","email","profile","roles"
                }
            }
        };

        var scopes = new Scope[]
            {
                StandardScopes.OpenId,
                StandardScopes.ProfileAlwaysInclude,
                StandardScopes.EmailAlwaysInclude,
                new Scope
                {
                    Name="roles",
                    Claims=new List<ScopeClaim>
                    {
                        new ScopeClaim("role")
                    },
                    Type=ScopeType.Identity
                }
            };

        var factory = new IdentityServerServiceFactory();
        factory.UseInMemoryClients(clients);
        factory.UseInMemoryScopes(scopes);
        factory.UseInMemoryUsers(users);

        var cert = LoadCertificate();

        app.UseIdentityServer(new IdentityServerOptions
        {
            SiteName = "NDC Demo",
            SigningCertificate = cert,
            Factory = factory,
            AuthenticationOptions = new AuthenticationOptions
            {
                IdentityProviders = ConfigureAdditionalIdentityProviders,
                EnableAutoCallbackForFederatedSignout = true
            }
        });
    }

    public static void ConfigureAdditionalIdentityProviders(IAppBuilder app, string signInAsType)
    {
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            AuthenticationType = "aad",
            Caption = "Azure AD",
            SignInAsAuthenticationType = signInAsType,

            Authority = "https://login.microsoftonline.com/04e14a2c-0e9b-42f8-8b22-3c4a2f1d8800",
            ClientId = "eca61fd9-f491-4f03-a622-90837bbc1711",
            RedirectUri = "https://localhost:44333/core/aadcb",
        });
    }

    static X509Certificate2 LoadCertificate()
    {
        var baseFolder = AppDomain.CurrentDomain.BaseDirectory;
        string certificatePath = $"{baseFolder}\Certificates\mycompanyname.pfx";
        return new X509Certificate2(certificatePath, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    }
}

然后我们可以通过以下请求与 IdentityServer3 进行交互:

https://localhost:44333/connect/authorize?response_type=id_token&client_id=mvc&redirect_uri=http://localhost:9000&scope=openid+email+profile+roles&nonce=123

请告诉我是否有帮助。

原来这个问题与 Katana OIDC MW 中的死锁错误有关。 解决方法是创建自定义 IConfigurationManager 并在启动时手动获取元数据。与Thinktecture提出的类似。

https://github.com/IdentityServer/IdentityServer3/blob/master/source/Host.Configuration/Extensions/SyncConfigurationManager.cs

替换 OpenIdConnectConfiguration



var manager = new SyncConfigurationManager(new ConfigurationManager < OpenIdConnectConfiguration > (Settings.AADAuthority + "/.well-known/openid-configuration"));

然后将管理器添加到 OpenIdAuthenticationOptions



    var aad = new OpenIdConnectAuthenticationOptions
                {
                    AuthenticationType = "AzureAd",
                    Caption = "Marquis Azure AD",
                    SignInAsAuthenticationType = signInAsType,
                    PostLogoutRedirectUri = Settings.LogoutRedirect,
                    Authority = Settings.AADAuthority,
                    ClientId = Settings.AADClientId,
                    RedirectUri = Settings.AADRedirectUrl,
                    ConfigurationManager = manager
                };