Получение несанкционированной html-страницы IIS вместо несанкционированного ответа веб-API для несанкционированного статуса

У меня есть приложение веб-API, размещенное на IIS 10 (Windows Server 2016). Приложение имеет API для входа. API-интерфейс входа украшен настраиваемым атрибутом фильтра проверки подлинности, который реализует IAuthenticationFilter.

[RoutePrefix("api/login")]
[AllowUnAuthorized]
[AuthenticationFilter]

public class LoginController : ApiController
{

    [HttpPost]
    public IHttpActionResult Login()
    {
        //Code to return token if passed authentication in the Authentication Filter
    }
 }   

Если учетные данные для входа (имя пользователя и пароль) недействительны, атрибут фильтра аутентификации устанавливает ErrorResult в контексте, который возвращает код состояния 401 ("Неавторизовано") с ответным сообщением.

public class AuthenticationFilter : Attribute, IAuthenticationFilter
{
    public bool AllowMultiple => false;

    public async Task AuthenticateAsync(HttpAuthenticationContext context, 
    CancellationToken cancellationToken)
    {
        HttpRequestMessage request = context.Request;
        AuthenticationHeaderValue authorization = 
         request.Headers.Authorization;

        if (authorization == null)
        {
            return;
        }
        if (authorization.Scheme != "Basic")
        {
            return;
        }


        Tuple<string, string> credentials = 
        ExtractCredentials(request.Headers);
        if (credentials == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid 
            credentials", request);                
            return;
        }
        string userName = credentials.Item1;
        string password = credentials.Item2;


        IAuthenticationService 
        service=container.Resolve<IAuthenticationService>();
        var user = service.GetUser(userName, password);
        if (user ==  null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);                
            return;
        }

        //Code to set principal if authentication passed
}

Это код класса AuthenticationFailureResult.

internal class AuthenticationFailureResult : IHttpActionResult
{
    public string ReasonPhrase { get; private set; }

    public HttpRequestMessage Request { get; private set; }

    public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
    {
        ReasonPhrase = reasonPhrase;
        Request = request;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute());
    }

    private HttpResponseMessage Execute()
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        response.RequestMessage = Request;
        response.ReasonPhrase = ReasonPhrase;
        return response;
    }
}

Этот код работал нормально и возвращал код состояния 401 вместе с сообщением, как указано в фразе причины. Однако я не знаю, из-за какого изменения API внезапно возвращает html-страницу, которая обычно возвращается IIS, с сообщением «401 — Несанкционировано: доступ запрещен из-за неверных учетных данных». вместо ответа об ошибке, установленного в фильтре аутентификации. Обратите внимание, что тот же API работает должным образом при работе в IISExpress.

Что я сделал до сих пор:

  1. Проверил Web.config и убедился, что для режима CustomErrors установлено значение «Вкл.».
  2. Убедился, что «Анонимная аутентификация» включена в разделе «Аутентификация» для сайта в IIS.
  3. Добавлено следующее в Web.config

    <system.webServer>
      <modules runAllManagedModulesForAllRequests = "true"/>
    </system.webServer>
    

Как ни странно, веб-API возвращает правильный ответ JSON при прохождении аутентификации.

Редактировать 1:

Вот метод ChallengeAsync

public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            var challenge = new AuthenticationHeaderValue("Basic");
            context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result);
            return Task.FromResult(0);
        }

Реализация AddChallengeOnUnauthorizedResult

public class AddChallengeOnUnauthorizedResult : IHttpActionResult
    {
        public AddChallengeOnUnauthorizedResult(AuthenticationHeaderValue challenge, IHttpActionResult innerResult)
        {
            Challenge = challenge;
            InnerResult = innerResult;
        }

        public AuthenticationHeaderValue Challenge { get; private set; }

        public IHttpActionResult InnerResult { get; private set; }

        public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response = await InnerResult.ExecuteAsync(cancellationToken);

            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                // Only add one challenge per authentication scheme.
                if (!response.Headers.WwwAuthenticate.Any((h) => h.Scheme == Challenge.Scheme))
                {
                    response.Headers.WwwAuthenticate.Add(Challenge);
                }
            }

            return response;
        }
    }

Не могли бы вы опубликовать более подробные коды о методе ChallengeAsync AuthenticationFilter? Интерфейс IAuthenticationFilter содержит два метода: AuthenticateAsync и ChallengeAsync. Это может быть более легко воспроизвести проблему.

Brando Zhang 28.05.2019 04:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
1 016
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Решение заключалось в добавлении ниже двух настроек в Web.config.

 <system.webServer>
            <httpErrors existingResponse = "PassThrough" />
            <modules runAllManagedModulesForAllRequests = "true" />
  </system.webServer>

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