Использовать множественную аутентификацию на предъявителя JWT

Возможно ли поддерживать несколько 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
                };
        }

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

Ответ 1

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

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] атрибутов [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")] для некоторых действий.