Получение неавторизованной html-страницы IIS вместо неавторизованного ответа веб-API для неавторизованного статуса - PullRequest
0 голосов
/ 27 мая 2019

У меня есть приложение веб-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;
        }
    }

1 Ответ

0 голосов
/ 15 июня 2019

Решением было добавление ниже двух настроек в Web.config.

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