Не удается проверить JWT или access_token в API с помощью IdentityServer4

#c# #authentication #asp.net-core #identityserver4 #openid-connect

#c# #аутентификация #asp.net-core #identityserver4 #OpenID-подключиться

Вопрос:

Я работаю над созданием некоторых новых функциональных возможностей там, где у нас есть существующая система. Наша цель — заставить разные Angular SPA взаимодействовать с API, чтобы представить новый интерфейс для нашего устаревшего приложения. Команда настроила IdentityServer4 на использование устаревшего приложения для проверки учетных данных.

SPA, написанный на Angular 7, использует неявный поток для аутентификации. Тип ответа — «token id_token» Мне удалось заставить этот поток работать настолько, чтобы пользователь, не прошедший проверку подлинности, заходил на сайт, переходил на экраны аутентификации IdentityServer, входил в систему с правильными учетными данными, а затем перенаправлялся обратно в приложение. Когда я получаю токен обратно, объект claims имеет единственное значение для aud , client_id для SPA, например, spa-client. Access_token и id_token оба являются JWT с RS256 в качестве метода подписи. Наконец, я создал перехватчик в SPA для отправки JWT (на самом деле он просто использует любое значение, отправленное обратно как access_token) в качестве токена «носителя» в запросах API.

Теперь я создал приложение WebAPI на .NET Core 2.2 для создания API-сервиса, который будет использоваться SPA. Это приложение использует IdentityServer4.Пакет AccessTokenValidation для «защиты» API Я прочитал раздел в документах IdentityServer4. В моем ConfigureServices методе я написал следующее для настройки аутентификации:

 services    
    .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication(options =>
    {
        if (string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.Authority)) throw new ConfigurationException("", nameof(serviceConfiguration.Authentication.Authority), "An authority must be defined.");
        if (string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.ApiName)) throw new ConfigurationException("", nameof(serviceConfiguration.Authentication.ApiName), "An api name must be defined.");

        options.Authority = serviceConfiguration.Authentication.Authority;
        options.ApiName = serviceConfiguration.Authentication.ApiName;

        if (!string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.ApiSecret))
        {
            options.ApiSecret = serviceConfiguration.Authentication.ApiSecret;
        }

        options.RequireHttpsMetadata = false;
        options.SupportedTokens = SupportedTokens.Both;
    }
  

serviceConfiguration является ли строго типизированным представлением моего JSON appsettings.json

Я понимаю, что с options.SupportedTokens = SupportedTokens.Both проверит JWT и проведет самоанализ.

Теперь, когда все это настроено, я взял простой пример, ValuesController который создается шаблоном API, и добавил к нему [Authorize] атрибут. Выполнение простого запроса GET к этой конечной точке в Postman возвращает 401, как я и ожидал.

Затем я пытаюсь войти в SPA и перейти на тестовую страницу, которая будет делать то же самое, но с перехватчиком, у которого будет токен-носитель, access_token или, в основном, JWT. Я все еще получаю 401 от службы.

Просматривая журналы, выводимые службой, я не вижу ничего конкретного, что было бы полезно:

информация: Microsoft.AspNetCore.Hosting.Внутренний.Параметры запуска запроса WebHost[1] HTTP/ 1.1http://localhost:5001/api/values информация: Microsoft.AspNetCore.Hosting.Внутренний.Параметры запуска запроса WebHost[1] HTTP/ 1.1http://localhost:5001/api/values информация: Microsoft.AspNetCore.Cors.Инфраструктура.CorsService[4] Выполнение политики CORS успешно. информация: Microsoft.AspNetCore.Cors.Инфраструктура.CorsService[4] Выполнение политики CORS успешно. информация: Microsoft.AspNetCore.Hosting.Внутренний.Запрос WebHost [2] завершен в 61.1352ms 204 информация: Microsoft.AspNetCore.Hosting.Внутренний.Запрос WebHost [2] завершен в 61.1272ms 204 информация: Microsoft.AspNetCore.Hosting.Внутренний.WebHost[1] Запрос, запускающий HTTP / 1.1 GEThttp://localhost:5001/api/values информация о приложении / json: Microsoft.AspNetCore.Hosting.Внутренний.WebHost[1] Запрос, запускающий HTTP / 1.1 GEThttp://localhost:5001/api/values информация о приложении / json: Microsoft.AspNetCore.Cors.Инфраструктура.CorsService[4] Выполнение политики CORS успешно. информация: Microsoft.AspNetCore.Cors.Инфраструктура.CorsService[4] Выполнение политики CORS успешно. информация: Microsoft.AspNetCore.Маршрутизация.EndpointMiddleware[0] Примеры выполнения конечной точки.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web)’ информация: Microsoft.AspNetCore.Маршрутизация.EndpointMiddleware[0] Примеры выполнения конечной точки.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web)’ информация: Microsoft.AspNetCore.Mvc.Internal.Маршрут ControllerActionInvoker[1] соответствует {action = «Get», controller = «Values»}. Примеры выполнения действий.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web) информация: Microsoft.AspNetCore.Mvc.Internal.Маршрут ControllerActionInvoker[1] соответствует {action = «Get», controller = «Values»}. Примеры выполнения действий.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web) информация: Microsoft.AspNetCore.Авторизация.DefaultAuthorizationService по умолчанию[2] Сбой авторизации. информация: Microsoft.AspNetCore.Авторизация.DefaultAuthorizationService по умолчанию[2] Не удалось выполнить авторизацию. информация: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] Сбой авторизации для запроса в filter ‘Microsoft.AspNetCore.Mvc.Авторизация.Авторизуйте фильтр’. информация: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3] Не удалось выполнить авторизацию запроса в filter ‘Microsoft.AspNetCore.Mvc.Авторизация.Авторизуйте фильтр’. информация: Microsoft.AspNetCore.Mvc.ChallengeResult[1] Выполнение ChallengeResult с использованием схем аутентификации (). информация: Microsoft.AspNetCore.Mvc.ChallengeResult[1] Выполнение ChallengeResult с помощью authentication schemes (). информация: IdentityServer4.Проверка доступа.IdentityServerAuthenticationHandler[12] Схема аутентификации: предъявитель был оспорен. информация: IdentityServer4.Проверка доступа.IdentityServerAuthenticationHandler[12] Схема аутентификации: предъявитель был оспорен. информация: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] Примеры выполненных действий.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web) за 166,3038мс информация: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] Примеры выполненных действий.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web) за 162.8827 мс информация: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Примеры выполненных конечных точек.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web)’ информация: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Примеры выполненных конечных точек.TestApp.API.Web.Controllers.ValuesController.Получить (Примеры.TestApp.API.Web)’ информация: Microsoft.AspNetCore.Hosting.Внутренний.Запрос WebHost [2] завершен за 459.6677 мс 401 информация: Microsoft.AspNetCore.Hosting.Внутренний.Запрос WebHost [2] завершен за 473.7648 мс 401

Установка для ведения журнала значения «Трассировка» больше ничего не показала.

Я попытался зайти в Postman, чтобы посмотреть, смогу ли я провести самоанализ токена вручную. Я настроил авторизацию на basic и установил имя пользователя на «test-api», идентификатор api и пароль, которые я установил в его клиентском секрете. В теле a установите для него значение x-www-form-urlencoded с ключом «token» и значением access_token. Я получаю 200 одобрений с утверждениями вместе с «active: true». Похоже, это должно быть хорошо, не так ли?

Я не владею реализацией IdentityServer, поэтому я не совсем уверен, что происходит на этом конце, за исключением возможности входа в пользовательский интерфейс администратора. Я вошел в пользовательский интерфейс администратора для сервера идентификации и дважды проверил настройки для клиента и API. Клиенту предоставляется область «api», а API получает ту же область «api». Это показано в области видимости, которая отправляется обратно в ответе самоанализа, а также в токене, который я получаю от клиента.

Я также пытался установить options.SupportedTokens = SupportedTokens.Reference и options.SupportedTokens = SupportedTokens.JWT . Ни в том, ни в другом не было никаких изменений. 🙁

Что я делаю не так? Это проблема конфигурации или я идиот (вероятно, последнее).

РЕДАКТИРОВАТЬ: ПОВТОРНО использовать access_token и id_token

Я был неправ в исходном вопросе. Токены разные (мне нужно посмотреть не только на часть заголовка).

Аудитория странная. Я никогда не обращал внимания на возможную разницу здесь при декодировании. Мои способности восприятия, должно быть, отстой!

Токен доступа имеет aud: «http:///resources «У id_token есть aud: «spa-клиент»

Ответ №1:

Access_token и id_token являются одинаковыми и представляют собой JWT с RS256 в качестве метода подписи.

Access_token и id_token не должны совпадать. Для id_token aud утверждением в токене должно быть имя клиента, но в токене доступа ваше имя api должно быть включено в aud , чтобы ваш ресурс api мог подтвердить, что токен доступа выдается для выполнения «моих» вызовов api. Вы можете использовать онлайн-инструмент, подобный jwt.io , для декодирования утверждений в токенах JWT. Поскольку вы не опубликовали конфигурацию client amp; IDS4, вам следует проверить тип ответа, область видимости … При использовании Fiddler для отслеживания запроса, он должен выглядеть :

 GET /connect/authorize/callback?client_id=jsamp;redirect_uri=http%3A%2F%2Flocalhost%3A5003%2Fcallback.htmlamp;response_type=id_token%20tokenamp;scope=openid%20profile%20api1amp;state=xxxxxxxxxxxxxxxamp;nonce=xxxxxxxxxxxxxxxxxxx
  

Кроме того, из документа :http://docs.identityserver.io/en/latest/topics/grant_types.html

Для приложений на основе JavaScript неявное использование больше не рекомендуется. Вместо этого используйте код авторизации с помощью PKCE.

Вы можете нажать здесь, чтобы посмотреть пример кода code flow.

Обновить :

аудитория токена доступа также должна включать имя api, помимо "http:///resources :

введите описание изображения здесь

Вы могли бы нажать здесь, чтобы посмотреть примеры кода.

Комментарии:

1. Никогда не смотрел на токены за пределами раздела encoded header, так что это было неправильное предположение с моей стороны. Я обновил вопрос дополнительной информацией относительно этого. Аудитория в access_token выглядит странно, и я пытаюсь выяснить, как она получает это значение. Кроме того, я понимаю о неявном потоке. Это было не мое решение: ( Какие значения конфигурации были бы полезны для отладки этого?

2. @MikeG , смотрите Ответ на обновление , аудитория токена доступа также должна включать имя api, помимо «http:///resources :

3. Отметьте свой ответ как правильный, потому что ваше обновление также было проблемой. Основная проблема заключалась в том, что я случайно использовал app.UseAuthentication() and app.UseMvc() в Configure методе. 🙁 🙁