У меня правильно работает приложение 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, но я не уверен, что это допустимая конфигурация?