Сбой аутентификации ASP.NET Core Multiple JWTBearer - PullRequest
1 голос
/ 26 апреля 2019

У меня правильно работает приложение ASP.NET Core 2.2 с использованием конфигурации аутентификации JwtBearer с Identity Server 4. Все работало нормально, пока я не хотел обрабатывать несколько прав доступа с помощью атрибута [Authorize].

Я просмотрел несколько потоков и вопросов по этому поводу и посмотрел документацию: https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-2.2&tabs=aspnetcore2x#use-multiple-authentication-schemes точно такой же код не работает и выдает следующую ошибку:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden]'. ---> System.IO.IOException: IDX20804: Unable to retrieve document from: '[PII is hidden]'. ---> System.Net.Http.HttpRequestException: No connection could be made because the target machine actively refused it ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Threading.Tasks.ValueTask1.get_Result() at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Threading.Tasks.ValueTask1.get_Result()
at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask1 creationTask) at System.Threading.Tasks.ValueTask1.get_Result()
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts) at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel) --- End of inner exception stack trace --- at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel) at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel) at Microsoft.IdentityModel.Protocols.ConfigurationManager1.GetConfigurationAsync(CancellationToken cancel)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.ConfigurationManager1.GetConfigurationAsync(CancellationToken cancel) at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() at Microsoft.AspNetCore.Authentication.AuthenticationHandler1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
at Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter.OnAuthorizationAsync(AuthorizationFilterContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at JQ.GrupoFontana.API.Startup.<>c.<<Configure>b__9_1>d.MoveNext() in C:\Users\carlostorrecillas\Documents\git\jq.grupofontana.api\JQ.GrupoFontana.API\Startup.cs:line 264
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.InvokeCore(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3073.2088ms 500 text/html; charset=utf-8

Пример заголовка авторизации:

Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ijk4NDM3ZDYxM2Y3N2NhNmFmMzViZWRkYzNhOTA5MDFhIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NTYyOTY0MTcsImV4cCI6MTU1NjMwMDAxNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDoxMTcxMCIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjExNzEwL3Jlc291cmNlcyIsImdydXBvZm9udGFuYWFwaSJdLCJjbGllbnRfaWQiOiJuZWdyb2NhcmJvbiIsInN1YiI6IjI1ZjExN2M5LWJjYzgtNDU3Ny1iNzIwLTk5YmVjYTlmZTk4MyIsImF1dGhfdGltZSI6MTU1NjI5NjQxNywiaWRwIjoibG9jYWwiLCJlbWFpbCI6ImluZm9AanVzdC1xdWFsaXR5LmNvbSIsInVzZXJuYW1lIjoianVzdHF1YWxpdHlAbmVncm9jYXJib24uZXMiLCJzY29wZSI6WyJvcGVuaWQiLCJwcm9maWxlIiwiZ3J1cG9mb250YW5hYXBpIl0sImFtciI6WyJwd2QiXX0.RofpWBaFKFaS9W5w6kjxVI6lfr7aWChIMHht3ibZ5LmTarAsGGoof-9GpWZxL3D9KfjoEC9gcmVIA7saB-Yikvz6i3yvHYsqhMkg7cLaBlUiz6lEpLQOS1-vYRYou0veyvI_EmSkZb9k00ErjA4BrNeb0kw3tL3PJI9A2nznnJPBU8hT7xiXeabQ9ROuuqxJU-GkP_3yr88CVfwuKiU8ur5xAbsLDyUCYiSL0DMbvoLhvLVdkHTJTuWcvfUcEK3Vidv38v490XZs7l2oI14ptA1vamIQ8iE_Pkb_NNv3S_F0hWmLHBWjaqGRlRdUE7R2kfFETRJdT6izzGOompuQwA

Что хорошо. Код в API у меня сейчас:

services.AddAuthentication("authority1")
            .AddJwtBearer("authority1", options =>
            {
                options.Authority = "http://localhost:11710";
                options.Audience = "myaudience";
                options.RequireHttpsMetadata = false;
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        if (context.Request.Path.Value.StartsWith("/hub", StringComparison.InvariantCultureIgnoreCase))
                        {
                            context.Token = context.Request.Query["access_token"];
                        }

                        return Task.CompletedTask;
                    },
                    OnTokenValidated = context =>
                    {
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        return Task.CompletedTask;
                    },
                    OnChallenge = context =>
                    {
                        return Task.CompletedTask;
                    }
                };
            })
            .AddJwtBearer("authority2", options =>
            {
                options.Authority = "http://localhost:11910";
                options.Audience = "myaudience";
                options.RequireHttpsMetadata = false;
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        if (context.Request.Path.Value.StartsWith("/hub", StringComparison.InvariantCultureIgnoreCase))
                        {
                            context.Token = context.Request.Query["access_token"];
                        }

                        return Task.CompletedTask;
                    },
                    OnTokenValidated = context =>
                    {
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        return Task.CompletedTask;
                    },
                    OnChallenge = context =>
                    {
                        return Task.CompletedTask;
                    }
                };
            });

            services.AddAuthorization(options =>
            {
                options.DefaultPolicy = new AuthorizationPolicyBuilder("authority1", "authority2").RequireAuthenticatedUser()
                                                                                    .Build();
            });

Вы можете игнорировать /hub чек, так как он имеет дело с токенами и SignalR. Я добавил себе точку останова к каждому из событий, чтобы посмотреть, где происходит сбой, и последовательность (обратите внимание, что authority1 приложение работает, а authority2 в данный момент остановлено):

authority1.onMessageReceived - OK
authority1.onTokenValidated - OK
authority2.onMessageReceived - OK
authority2.onAuthenticationFailed - Method completes then I get the exception

Я не уверен, что проблема в том, что мне нужны все права доступа для какой-либо проверки / связи (я бы так не думал), или в том, что в самом коде ASP.NET действительно есть ошибка - что эй, это также может быть так. Я не уверен, что пропущу какую-либо другую конфигурацию с точки зрения API, но я бы сказал, что все готово.

Я использую стандартный атрибут [Authorize] в моих контроллерах без каких-либо вещей, связанных с аутентификацией - я пробовал, но это тоже не сработало.

Если кто-нибудь из вас сталкивался с этой проблемой, я был бы очень признателен за помощь.

Большое спасибо!

ОБНОВЛЕНИЕ:

После еще нескольких копаний я смог увидеть этот обходной путь:

https://github.com/aspnet/Security/issues/1680#issuecomment-370416251

установка context.NoResult() в OnAuthenticationFailed, но я не уверен, что это допустимая конфигурация?

...