Тестирование интеграции XUnit с Identityserver: токен, полученный от Identityserver, не может соответствовать ключу

В настоящее время я пытаюсь реализовать тестирование интеграции в среде с двумя серверами:

  • Сервер API.NET Core
  • Сервер аутентификации IdentityServer4

Благодаря долгой борьбе мне удалось заставить этих двоих общаться друг с другом, однако IdentityServer выдает следующую ошибку при попытке подтвердить токен JWT (через API):

Носитель не был аутентифицирован. Сообщение об ошибке: IDX10501: Ошибка проверки подписи. Невозможно сопоставить ключ: kid: '8C1D5950D083E20D4B20DE9B37AC71FAEF679469'.

Я постараюсь сделать пример кода кратким:

При запуске XUnit я настраиваю и создаю клиентов для обоих TestServer.

    public APITestBase(ITestOutputHelper output)
    {
        _output = output;

        var apicon = new ConfigurationBuilder()
            .AddJsonFile("apisettings.json", optional: true, reloadOnChange: true)
            .Build();

        var authcon = new ConfigurationBuilder()
            .AddJsonFile("authsettings.json", optional: true, reloadOnChange: true)
            .Build();

        _authServer = new TestServer(new WebHostBuilder()
            .UseConfiguration(authcon)
            .ConfigureLogging(x => x.AddXUnit(_output))
            .UseEnvironment("Development")
            .UseStartup<Auth.Startup>());

        _authClient = _authServer.CreateClient();

        _server = new TestServer(new WebHostBuilder()
            .UseConfiguration(apicon)
            .ConfigureLogging(x => x.AddXUnit(_output))
            .UseEnvironment("Test")
            .ConfigureServices(
                  services => {
//Here, I'm adding an httpclienthandler. In the application I will use this as JWTBackChannelHandler. This allows communication between the two servers
                      services.AddSingleton<HttpMessageHandler>(_authServer.CreateHandler());
                  })
            .UseStartup<Api.Startup>());

        _client = _server.CreateClient();

        APIConfig = new Cnfg();
         
        apicon.Bind("APIConfig", APIConfig);

        //Make users in api

    }

Вот настоящий тест, который я пытаюсь запустить

        [Fact]
        public async Task ApplyTest()
        {
            _client.SetBearerToken(await GetAccessToken());

            // Act
            var response = await _client.GetAsync($"{APIConfig.ApiBaseUrl}api/call/");
             response.EnsureSuccessStatusCode();
        }

А вот GetAccessToken, который возвращает токен JWT, который интеграция использует для идентификации себя как пользователя... По крайней мере, таков план.

        protected async Task<string> GetAccessToken()
    {
        var disco = await _authClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest()
        {
            Address = _authServer.BaseAddress.ToString(),
            Policy =
                {
                    ValidateIssuerName = false
                }
        });

        if (!String.IsNullOrEmpty(disco.Error))
        {
            throw new Exception(disco.Error);
        }
        var response = await _authClient.RequestPasswordTokenAsync(new PasswordTokenRequest
        {
            Address = disco.TokenEndpoint,
            GrantType = "password",
            ClientId = "api",

            UserName = "test@test.nl",
            Password = "test"
        });

        return response.AccessToken;
    }

Единственная различимая разница, которую я могу найти между токеном JWT, сгенерированным с помощью этой функции, и токеном обычного запроса веб-сайта, заключается в том, что открытый ключ отсутствует (согласно jwt.io).

Наконец, поскольку я думаю, что этот бит может быть полезен, вот часть API Startup.cs, где я принудительно использую JWTBackChannelHandler

if (Environment.EnvironmentName == "Test")
            {
                services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                    .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, o =>
                    {
                        o.JwtBackChannelHandler = _identityServerMessageHandler;
                        o.RequireHttpsMetadata = false;
                    })
                    .AddApiKeyAuthenication(o =>
                    {
                        o.Keys.Add("****".ToSha256());
                        o.Keys.Add("****".ToSha256());
                    });
            }

Заранее большое спасибо за вашу помощь, я вроде как дошел до предела с этим. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация, и я буду рад ее предоставить.

1 ответ

Еще через 2 часа копания обнаружил, что нужно добавить

o.Authority = identityServerOptions.Address.AbsoluteUri;

К файлу AddIdentityServerAuthentication.

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

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