ASP.NET core 2.2: каково ожидаемое поведение ChallengeResult, когда настроено несколько схем проверки подлинности?

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

Нам нужно обработать такой сценарий, потому что у нас есть приложение ASP.NET core 2.2, предоставляющее некоторые методы действий (мы используем промежуточное программное обеспечение MVC), которые должны использоваться SPA angularjs, который полагается на аутентификацию файлов cookie, и некоторые сторонние приложения, которые используют аутентификацию. механизм, основанный на заголовке HTTP-запроса авторизации. Обратите внимание, что вовлеченные методы действия одинаковы для обоих пользователей означает, что каждый из них должен разрешать аутентификацию с использованием как файла cookie, так и пользовательской схемы на основе заголовка HTTP-запроса авторизации. Мы знаем, что, вероятно, это не оптимальный дизайн, но мы не можем изменить общую архитектуру.

Эта документация, похоже, подтверждает, что то, чего мы хотели бы достичь, вполне возможно с использованием ядра ASP.NET 2.2. К сожалению, аутентификация cookie, используемая приложением пользовательского интерфейса, и пользовательская аутентификация, используемая третьими лицами, должны вести себя по-разному в случае проблемы аутентификации, и их ожидаемое поведение несовместимо друг с другом: приложение пользовательского интерфейса должно перенаправлять пользователя на форму входа. , в то время как стороннее приложение ожидает необработанный ответ с кодом состояния 401. Документация, указанная выше, не дает четкого объяснения обработки ChallengeResult, поэтому мы решили поэкспериментировать с тестовым приложением.

Мы создали два поддельных обработчика аутентификации:

public class FooAuthenticationHandler : IAuthenticationHandler
  {
    private HttpContext _context;

    public Task<AuthenticateResult> AuthenticateAsync()
    {
      return Task.FromResult(AuthenticateResult.Fail("Foo failed"));
    }

    public Task ChallengeAsync(AuthenticationProperties properties)
    {
      _context.Response.StatusCode = StatusCodes.Status403Forbidden;
      return Task.CompletedTask;
    }

    public Task ForbidAsync(AuthenticationProperties properties)
    {
      return Task.CompletedTask;
    }

    public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
    {
      _context = context;
      return Task.CompletedTask;
    }
  }
public class BarAuthenticationHandler : IAuthenticationHandler
  {
    private HttpContext _context;

    public Task<AuthenticateResult> AuthenticateAsync()
    {
      return Task.FromResult(AuthenticateResult.Fail("Bar failed"));
    }

    public Task ChallengeAsync(AuthenticationProperties properties)
    {
      _context.Response.StatusCode = StatusCodes.Status500InternalServerError;
      return Task.CompletedTask;
    }

    public Task ForbidAsync(AuthenticationProperties properties)
    {
      return Task.CompletedTask;
    }

    public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
    {
      _context = context;
      return Task.CompletedTask;
    }
  }

Мы зарегистрировали схемы аутентификации внутри метода ConfigureServices следующим образом:

public void ConfigureServices(IServiceCollection services)
    {
      services
        .AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

      services.AddAuthentication(options => 
      {
        options.DefaultChallengeScheme = "Bar";
        options.AddScheme<FooAuthenticationHandler>("Foo", "Foo scheme");
        options.AddScheme<BarAuthenticationHandler>("Bar", "Bar scheme");
      });
    }

Это наш конвейер промежуточного программного обеспечения:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }
      else
      {
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
      }

      app.UseHttpsRedirection();

      app.UseAuthentication();

      app.UseMvc();
    }

и, наконец, мы создали контроллер с методом действия, требующим аутентификации:

[Route("api/[controller]")]
  [ApiController]
  public class ValuesController : ControllerBase
  {
    // GET api/values/5
    [HttpGet("{id}")]
    [Authorize(AuthenticationSchemes = "Foo,Bar")]
    public ActionResult<string> Get(int id)
    {
      return "value";
    }
  }

Мы заметили, что:

  • и FooAuthenticationHandler, и BarAuthenticationHandler вызываются для обработки ChallengeResult
  • порядок FooAuthenticationHandler перед BarAuthenticationHandler и зависит от атрибута Authorize (если вы поменяете схемы аутентификации внутри атрибута Authorize, то сначала вызывается BarAuthenticationHandler)
  • вызывающая сторона получает необработанный ответ с кодом состояния 500, но это зависит только от порядка, в котором вызываются обработчики авторизации.
  • вызов options.DefaultChallengeScheme = "Bar"; имеет значение если и только если внутри атрибута [Authorize] свойство AuthenticationSchemes имеет значение нет. Если вы это сделаете, будет вызван только BarAuthenticationHandler, а FooAuthenticationHandler никогда не получит шанс аутентифицировать запрос или обработать вызов аутентификации.

Итак, вопрос в основном таков: когда у вас есть такой сценарий, как вы должны обрабатывать возможную «несовместимость» различных схем аутентификации в отношении обработки ChallengeResult, поскольку они вызывают обе?

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

Спасибо за помощь !

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
1 802
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Не следует указывать схемы в атрибуте Authorize. Вместо этого укажите одну схему по умолчанию и настройте прямой селектор.

Реализация селектора зависит от вашего случая, но обычно можно как-то разобраться, какая схема использовалась в запросе.

Например, вот пример настройки схемы OpenID Connect.

o.ForwardDefaultSelector = ctx =>
{
    // If the current request is for this app's API
    // use JWT Bearer authentication instead
    return ctx.Request.Path.StartsWithSegments("/api")
        ? JwtBearerDefaults.AuthenticationScheme
        : null;
};

Итак, что он делает, так это пересылает вызовы (и вообще все) обработчику JWT, если маршрут начинается с /api. Вы можете делать там любые проверки, заголовки и т.д.

Таким образом, в этом случае OpenID Connect и файлы cookie настроены по умолчанию для всего, но если получен вызов, который идет к API, используйте аутентификацию JWT.

В приведенном здесь примере передаются все «действия», которые вы можете выполнить с аутентификацией (запрос, запрет и т. д.). Вы также можете настроить селекторы вперед только для задач и т. д.

Делая так, как вы предлагаете, возможно ли дать обе обработчикам аутентификации возможность выполнить аутентификацию, но принудительно (на основе надлежащего условия) обрабатывать запрос аутентификации только один из них? Если это возможно, мы должны выбрать правильный обработчик для проверки подлинности в зависимости от типа получаемого вызова (если angularjs, то cookie, иначе пользовательский обработчик). Это правильно?

Enrico Massone 10.04.2019 15:18

Из любопытства, какие две схемы вы хотите поддержать?

juunas 10.04.2019 15:20

В настоящее время приложение написано на .NET 4.7.1 и представляет собой приложение ASP.NET MVC 5. Мы хотим перенести его на ASP.NET core 2.2. Весь механизм аутентификации является пользовательским, у нас в основном есть собственная реализация сервера идентификации. План верхнего уровня для миграции использует схему файлов cookie для клиентского приложения angularjs и пользовательскую схему, основанную на заголовке авторизации HTTP-запроса для сторонних приложений (вызовы сервер-сервер для вызовов клиент-сервер, выполняемые проектами, использующими нашу инфраструктуру). ).

Enrico Massone 10.04.2019 15:25

В настоящее время у нас есть несколько контроллеров ASP.NET web api 2, которые используются обе клиентом angularjs и сторонними интеграторами. Текущий (настраиваемый) механизм аутентификации выполняет несколько попыток аутентификации запроса, в основном проверяет наличие файла cookie и заголовка Authorize. Если он находит любой из них, он устанавливает идентификатор для принципала пользователя запроса, и запрос аутентифицируется. Мы пытаемся выяснить, как перенести эту реализацию на ядро ​​​​ASP.NET.

Enrico Massone 10.04.2019 15:29

помимо нашего конкретного производственного сценария, я хотел бы понять, как структура аутентификации ядра ASP.NET была разработана для обработки таких сценариев с несколькими настроенными схемами аутентификации, имеющими различное поведение в случае проблемы аутентификации (я имею в виду, что такое наилучшая практика — каков ожидаемый способ использования предоставленного API для аутентификации?).

Enrico Massone 10.04.2019 15:34

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