Identityserver4 API-аутентификация не работает должным образом

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

Аутентификация API выполняется через маркер канала идентификации сервера. Таким образом, аутентификация API отлично работает на локальном хосте, однако, когда я развертываю сервер идентификации на экземплярах контейнеров Azure, API перестает работать как из MVC, так и из Postman. Я получаю ошибку:

Произошло необработанное исключение при обработке запроса. WinHttpException: тайм-аут операции

System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() HttpRequestException: при отправке запроса произошла ошибка.

System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () IOException: IDX10804: невозможно получить документ из: ' http://taxrefund-identity.westeurope.azurecontainer.io/.well-known/openid-configuration'.

Microsoft.IdentityModel.Protocols.HttpDocumentRetriever + d__8.MoveNext () InvalidOperationException: IDX10803: невозможно получить конфигурацию из: ' http://taxrefund-identity.westeurope.azurecontainer.io/.well-known/openid-configuration'.

Microsoft.IdentityModel.Protocols.ConfigurationManager + d__24.MoveNext ()

Самое странное, что я могу без проблем получить доступ к конечной точке обнаружения через свой браузер.

Мой метод ConfigureServices:

   public void ConfigureServices(IServiceCollection services)
    {
        services.AddEntityFrameworkSqlServer()
                .AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                        sqlServerOptionsAction: sqlOptions =>{
                            sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
                        }), ServiceLifetime.Scoped
                 );
        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
        services.AddTransient<IEmailSender, EmailSender>();
        services.AddScoped<DatabaseInitializer>();
        services.AddCors();
        // Adds IdentityServer
        var cert = new X509Certificate2(Path.Combine(Environment.ContentRootPath, "idsrv3test.pfx"), "idsrv3test");
        services.AddIdentityServer()
            .AddSigningCredential(cert)
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddAspNetIdentity<ApplicationUser>()
            .Services.AddTransient<IProfileService, ProfileService>();

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        services.AddAuthentication()
            .AddGoogle("Google", options =>
            {
                options.ClientId = "**";
                options.ClientSecret = "**";
            })
            .AddMicrosoftAccount("Microsoft", options =>
            {
                options.ClientId = "**";
                options.ClientSecret = "**";
            });
        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(o =>
            {
                o.Authority = "http://taxrefund-identity.westeurope.azurecontainer.io/";
                o.ApiName = "Profile.API";
                o.ApiSecret = "**";
                o.RequireHttpsMetadata = false;
            });
        services.AddMvc();
        services.AddAntiforgery();
    }

Настройте метод:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, RoleManager<IdentityRole> roleManager, ApplicationDbContext context, UserManager<ApplicationUser> userManager)
    {
        loggerFactory.AddDebug();
        loggerFactory.AddConsole(LogLevel.Trace);
        loggerFactory.AddFile("logs.txt");

        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
        app.UseBrowserLink();
        app.UseCors(policy =>
        {
            policy.AllowCredentials();
            policy.AllowAnyOrigin();
            policy.AllowAnyHeader();
            policy.AllowAnyMethod();
            policy.WithExposedHeaders("WWW-Authenticate");
        });

        app.UseStaticFiles();
        app.UseIdentityServer();
        app.UseAuthentication();
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
        context.Database.Migrate();
        DatabaseInitializer.SeedData(roleManager);
    }

Конфигурация ресурса API:

new ApiResource("Profile.API", "Profile management API")
{
    UserClaims = { ClaimTypes.Role },
    ApiSecrets =
    {
        new Secret("**".Sha256())
    }
}

Я защищаю свой API следующим образом:

[Authorize(AuthenticationSchemes = "Bearer")]
[Route("api/Users")]
[Produces("application/json")]
public class ApplicationUsersAPIController : ControllerBase

Чтобы получить к нему доступ, я запрашиваю токен из конечной точки /connect/token (либо с учетными данными клиента, либо с помощью пароля / имени пользователя владельца ресурса), а затем использую его в заголовке авторизации для последующих запросов.

Я застрял с этой проблемой почти месяц - сейчас это расстраивает. Я прочитал все сообщения, связанные с этой проблемой, и ни одно из решений не помогло. Я пытался перейти на более ранние версии system.net.http, различные сертификаты и другие решения, которые помогали другим.

Также конечная точка без атрибута [Authorize] работает просто отлично.

Единственное, что я не пробовал, это установить SSL-сертификат и сделать мои URL-адреса https - я прочитал, что это не должно влиять на функциональность сервера идентификации. У меня сейчас нет реальной необходимости в этом, поэтому дайте мне знать, если это необходимо.

Если мне нужна дополнительная информация, дайте мне знать.

Очень признателен.

1 ответ

Решение

Окончательное решение состояло в том, чтобы изменить URL авторизации в AddIdentityServerAuthentication от:

services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(o =>
            {
                o.Authority = "http://taxrefund-identity.westeurope.azurecontainer.io/";
                o.ApiName = "Profile.API";
                o.ApiSecret = "**";
                o.RequireHttpsMetadata = false;
            });

Для того, чтобы:

   services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(o =>
                {
                    o.Authority = "http://localhost/"; //crucial part
                    o.ApiName = "Profile.API";
                    o.ApiSecret = "**";
                    o.RequireHttpsMetadata = false;
                });

Это действительно имеет смысл, поскольку в этом случае сервер идентификации и API-интерфейс работают в одном и том же экземпляре / процессе контейнера, поэтому он не может получить к себе доступ через URL-адрес DNS, а может получить доступ к самому себе через localhost URL.

Другие вопросы по тегам