Использовать несколько JWT Bearer Authentication

Можно ли поддерживать несколько эмитентов токенов JWT в ASP.NET Core 2? Я хочу предоставить API для внешней службы, и мне нужно использовать два источника токенов JWT - Firebase и настраиваемые эмитенты токенов JWT. В ядре ASP.NET я могу установить аутентификацию JWT для схемы аутентификации на предъявителя, но только для одного центра:

  services
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = "https://securetoken.google.com/my-firebase-project"
            options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidIssuer = "my-firebase-project"
                    ValidateAudience = true,
                    ValidAudience = "my-firebase-project"
                    ValidateLifetime = true
                };
        }

У меня может быть несколько эмитентов и аудиторий, но я не могу установить несколько органов власти.

AFAIK вы можете добавить любое количество свойств в JWT. Итак, ничто не мешает вам записать два имени эмитента в JWT. Проблема заключается в том, что вашему приложению необходимо знать оба ключа, если каждый эмитент использовал свой ключ для подписи.

Tim Biegeleisen 06.04.2018 15:58
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
99
1
34 072
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете полностью достичь того, чего хотите:

services
    .AddAuthentication()
    .AddJwtBearer("Firebase", options =>
    {
        options.Authority = "https://securetoken.google.com/my-firebase-project"
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = "my-firebase-project"
            ValidateAudience = true,
            ValidAudience = "my-firebase-project"
            ValidateLifetime = true
        };
    })
    .AddJwtBearer("Custom", options =>
    {
        // Configuration for your custom
        // JWT tokens here
    });

services
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Firebase", "Custom")
            .Build();
    });

Давайте рассмотрим различия между вашим кодом и этим.

AddAuthentication не имеет параметра

Если вы установите схему проверки подлинности по умолчанию, то при каждом отдельном запросе промежуточное программное обеспечение проверки подлинности будет пытаться запустить обработчик проверки подлинности, связанный со схемой проверки подлинности по умолчанию. Поскольку теперь у нас есть две возможные схемы аутентификации, запускать одну из них нет смысла.

Используйте другую перегрузку AddJwtBearer

Каждый метод AddXXX для добавления аутентификации имеет несколько перегрузок:

Теперь, поскольку вы дважды используете один и тот же метод аутентификации, но схемы аутентификации должны быть уникальными, вам необходимо использовать вторую перегрузку.

Обновите политику по умолчанию

Поскольку запросы больше не будут аутентифицироваться автоматически, добавление атрибутов [Authorize] к некоторым действиям приведет к тому, что запросы будут отклонены, и будет выдан HTTP 401.

Поскольку это не то, что мы хотим, потому что мы хотим дать обработчикам аутентификации возможность аутентифицировать запрос, мы меняем политику системы авторизации по умолчанию, указывая, что схемы аутентификации Firebase и Custom должны быть пытался для аутентификации запроса.

Это не мешает вам быть более строгими в отношении некоторых действий; Атрибут [Authorize] имеет свойство AuthenticationSchemes, которое позволяет вам переопределить, какие схемы аутентификации действительны.

Если у вас есть более сложные сценарии, вы можете использовать авторизация на основе политик. Я считаю, что официальная документация великолепна.

Представим, что некоторые действия доступны только для токенов JWT, выпущенных Firebase, и должны иметь заявку с определенным значением; вы можете сделать это так:

// Authentication code omitted for brevity

services
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Firebase", "Custom")
            .Build();

        options.AddPolicy("FirebaseAdministrators", new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Firebase")
            .RequireClaim("role", "admin")
            .Build());
    });

Затем вы можете использовать [Authorize(Policy = "FirebaseAdministrators")] для некоторых действий.

И последнее замечание: если вы перехватываете события AuthenticationFailed и используете что-либо, кроме первой политики AddJwtBearer, вы можете увидеть IDX10501: Signature validation failed. Unable to match key.... Это вызвано тем, что система проверяет каждый AddJwtBearer по очереди, пока не найдет совпадение. Обычно на ошибку можно не обращать внимания.

Требуется ли для этого изменить значение заголовка из firebase или специального решения? т.е. вместо Authorization : Bearer <token>, чтобы заголовок был, например, Authorization : Firebase <token>? Когда я попробовал это решение, я получил ошибку: «Для схемы« Bearer »не зарегистрирован обработчик аутентификации».

Rush Frisby 14.12.2018 21:38

Нет, заголовки менять не нужно. Сообщение об ошибке предполагает, что вы имеете в виду несуществующую схему аутентификации (носитель). В наших примерах две зарегистрированные схемы - это Firebase и Custom, которые являются первыми аргументами вызовов метода .AddJwtBearer.

Mickaël Derriey 15.12.2018 07:40

Это произошло потому, что кто-то поместил [Authorize (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] в методы контроллера. Это работает после того, как я изменил его на [Авторизовать]

Rush Frisby 16.12.2018 05:08

Есть ли какой-нибудь образец программы или ее можно скачать с github или где-нибудь для справки?

Ong Ming Soon 01.01.2019 07:21

Привет. Искал именно такое решение. К сожалению, я получаю исключение «Схема проверки подлинности не указана, и схема DefaultChallengeScheme не найдена». options.DefaultPolicy установлен нормально. Любые идеи?

terjetyl 05.03.2019 10:25

Это был в высшей степени полезный ответ, и он собрал воедино многое из того, что я видел повсюду.

Aron 02.08.2019 20:11

@AronW. У меня такая же ошибка. Вы нашли решение для ошибки, связанной с отсутствием схемы по умолчанию? пожалуйста, дайте мне знать

iRamesh 14.11.2019 18:52

Я тоже нашел этот ответ СУПЕР ПОЛЕЗНЫМ. Если бы я мог проголосовать за самый высший ответ, который я когда-либо видел, то это был бы этот. У меня он работает, но нужно очистить код. У меня есть несколько дополнительных фрагментов, которые могут быть полезны другим читателям, поэтому оставлю это как дополнительный ответ. В ASP.Net Core 3.1 вы получаете несколько неприятных граммов, которые загромождают журнал, но после их прочтения вы можете увидеть, что они имеют смысл и не о чем беспокоиться. stackoverflow.com/questions/58856735/… имеет неприятные граммы, которые я вижу.

No Refunds No Returns 12.02.2020 03:32

Я получаю следующую ошибку в ядре 3.1: «Не указана схема проверки подлинности, и схема DefaultAuthenticateScheme не найдена». Если я правильно понимаю, вы не хотите указывать схему по умолчанию. Как решить эту проблему

Pieter 18.02.2020 11:28

@Pieter, я думаю, что ни в атрибуте [Authorize], ни в политике авторизации явно не указаны схемы аутентификации, которые будут использоваться для аутентификации.

Mickaël Derriey 18.02.2020 23:17

В ядре 3.1 .AddAuthentication () должна иметь схему по умолчанию. auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; auth.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; И, кстати, порядок в de AddAuthorization имеет значение, если я прав

Pieter 20.02.2020 16:40

@Pieter, это неверно, схемы по умолчанию не требуются, как указано в моем ответе. Ваши схемы также показывают, что ваша установка никак не связана с вопросом. При необходимости задайте новый вопрос.

Mickaël Derriey 21.02.2020 20:42

Испытываются ли оба AuthenticationScheme для каждого звонка? (Мне не звонят ни один из моих .AddJwtBeaerer.)

Vaccano 24.04.2020 01:12

Политика авторизации определяет, какие схемы аутентификации «пробуются». Взяв последний пример кода выше, пустой атрибут [Authorize] будет использовать политику по умолчанию, следовательно, будет пробовать обе схемы, тогда как [Authorize(Policy = "FirebaseAdministrators")] будет пробовать только схему Firebase. Отсутствие политики на уровне действия, контроллера или глобального уровня означает, что конечная точка доступна для анонимных запросов, поэтому никакая схема не будет опробована.

Mickaël Derriey 25.04.2020 07:16

В ядре 3.1 DefaultPolicy используется только тогда, когда каждый тип конечной точки в ваших Startup UseEndpoints устанавливает RequireAuthorization (). (например, .UseEndpoints(rb => rb.MapControllers().RequireAuthorization()))

TylerOhlsen 27.04.2020 18:54

@TylerOhlsen, это неверно; хотя он и будет использоваться в описанном вами случае, он не единственный. Он также будет использоваться, если вы не укажете требование авторизации на уровне конечной точки, но украсите контроллеры и / или действия MVC пустым атрибутом [Authorize].

Mickaël Derriey 28.04.2020 00:11
gist.github.com/mac2000/ff95fc54bdc684646bb1de24ef07b333 на случай, если кому-то понадобится какой-то автономный пример, подход работает, также почти то же самое в документах - docs.microsoft.com/en-us/aspnet/core/security/authorization/‌…
mac 18.05.2020 13:27

Опыт, который я получаю, заключается в том, что обе конфигурации схемы проверяются, и любой сбой приводит к отключению всего запроса. Первый соответствует предоставленному токену, и я вижу, что OnTokenValidated выполняется. Затем по какой-то глупой причине он снова переходит к проверке, используя вторую схему, которая, конечно, терпит неудачу, и создается 401. Не знаю, для какого сценария это предназначено. Кто выдает токены, поддерживающие несколько схем ??!

Sam 07.07.2020 05:14

@Sam Я создал совершенно новый проект, следуя концепции моего ответа, и я не могу воспроизвести то, что вы испытываете. Да, обе схемы проверяются, что ожидается, но поскольку одна из них завершается успешно, общая авторизация считается успешной. См. Самый простой пример, который я мог придумать, в gist.github.com/mderriey/994d72a81f9f4324b32e68fec0705a2e.

Mickaël Derriey 10.07.2020 12:53

@ MickaëlDerriey Мы делаем что-то подобное вышеупомянутому. Кажется, это работает для проверки подлинности, но в итоге получается сценарий, в котором ClaimsPrincipal либо неправильно установлен, либо утверждения и удостоверения в ClaimsPrincipal не установлены. Есть идеи, почему это должно быть?

Jano du Toit 27.10.2020 12:49

этот ответ определенно направил меня в правильное русло, но я не смог заставить его работать и последовал за этой статьей. установка по умолчанию сработала docs.microsoft.com/en-us/aspnet/core/security/authorization/‌…

Kumar Garapati 03.11.2020 21:38

К вашему сведению, вам может потребоваться специальное промежуточное ПО для заполнения context.User, см. github.com/aspnet/Security/issues/1708#issuecomment-37656749‌ 1

Pedro Maia Costa 20.03.2021 17:20

Это продолжение ответа Микаэля Дерри.

В нашем приложении есть настраиваемое требование авторизации, которое мы решаем из внутреннего источника. Мы использовали Auth0, но переходим на аутентификацию учетной записи Microsoft с использованием OpenID. Вот слегка отредактированный код из нашего запуска ASP.Net Core 2.1. Для будущих читателей это работает на момент написания этой статьи для указанных версий. Вызывающий использует id_token из OpenID для входящих запросов, переданных как Bearer token. Надеюсь, это поможет кому-то другому, пытающемуся преобразовать полномочия личности, так же, как этот вопрос и ответ помогли мне.

const string Auth0 = nameof(Auth0);
const string MsaOpenId = nameof(MsaOpenId);

string domain = "https://myAuth0App.auth0.com/";
services.AddAuthentication()
        .AddJwtBearer(Auth0, options =>
            {
                options.Authority = domain;
                options.Audience = "https://myAuth0Audience.com";
            })
        .AddJwtBearer(MsaOpenId, options =>
            {
                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateAudience = true,
                    ValidAudience = "00000000-0000-0000-0000-000000000000",

                    ValidateIssuer = true,
                    ValidIssuer = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0",

                    ValidateIssuerSigningKey = true,
                    RequireExpirationTime = true,
                    ValidateLifetime = true,
                    RequireSignedTokens = true,
                    ClockSkew = TimeSpan.FromMinutes(10),
                };
                options.MetadataAddress = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0/.well-known/openid-configuration";
            }
        );

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes( Auth0, MsaOpenId )
        .Build();

    var approvedPolicyBuilder =  new AuthorizationPolicyBuilder()
           .RequireAuthenticatedUser()
           .AddAuthenticationSchemes(Auth0, MsaOpenId)
           ;

    approvedPolicyBuilder.Requirements.Add(new HasApprovedRequirement(domain));

    options.AddPolicy("approved", approvedPolicyBuilder.Build());
});

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