Несанкционированный вызов webapi возвращает страницу входа, а не 401

Как мне настроить мой проект mvc / webapi так, чтобы метод webapi, вызываемый из представления бритвы, не возвращал страницу входа в систему, когда она неавторизована?

Это приложение MVC5, которое также имеет контроллеры WebApi для вызовов через javascript.

Два метода ниже

[Route("api/home/LatestProblems")]      
[HttpGet()]
public List<vmLatestProblems> LatestProblems()
{
    // Something here
}

[Route("api/home/myLatestProblems")]
[HttpGet()]
[Authorize(Roles = "Member")]
public List<vmLatestProblems> mylatestproblems()
{
   // Something there
}

вызываются через следующий угловой код:

angular.module('appWorship').controller('latest', 
    ['$scope', '$http', function ($scope,$http) {         
        var urlBase = baseurl + '/api/home/LatestProblems';
        $http.get(urlBase).success(function (data) {
            $scope.data = data;
        }).error(function (data) {
            console.log(data);
        });
        $http.get(baseurl + '/api/home/mylatestproblems')
          .success(function (data) {
            $scope.data2 = data;
        }).error(function (data) {
            console.log(data);
        });  
    }]
);

Итак, я не вошел в систему, и первый метод успешно возвращает данные. второй метод возвращает (в функции успеха) данные, которые содержат эквивалент страницы входа в систему. то есть, что вы получили бы в mvc, если бы вы запросили действие контроллера, отмеченное [Авторизовать], и вы не вошли в систему.

Я хочу, чтобы он возвращал 401 неавторизованный, чтобы я мог отображать разные данные для пользователей в зависимости от того, вошли они в систему или нет. В идеале, если пользователь вошел в систему, я хочу иметь доступ к свойству User контроллера, чтобы я мог возвращать данные, специфичные для этого члена.

ОБНОВЛЕНИЕ: поскольку ни одно из приведенных ниже предложений, похоже, больше не работает (изменения в Identity или WebAPI), я создал необработанный пример на github, который должен проиллюстрировать проблему.


person Tim    schedule 22.11.2013    source источник


Ответы (15)


Существует две реализации AuthorizeAttribute, и вам нужно убедиться, что вы ссылаетесь на правильную реализацию для веб-API. Есть System.Web.Http.AuthorizeAttribute, который используется для веб-API, и System.Web.Mvc.AuthorizeAttribute, который используется для контроллеров с представлениями. Http.AuthorizeAttribute вернет ошибку 401, если авторизация не удалась, а Mvc.AuthorizeAttribute перенаправит на страницу входа.

Обновлено 26 ноября 2013 г.

Таким образом, похоже, что с MVC 5 все кардинально изменилось, как указал Брок Аллен в своей статье. Я предполагаю, что конвейер OWIN вступает во владение и вводит некоторое новое поведение. Теперь, когда пользователь не авторизован, возвращается статус 200 со следующей информацией в заголовке HTTP.

X-Responded-JSON: {"status":401,"headers":{"location":"http:\/\/localhost:59540\/Account\/Login?ReturnUrl=%2Fapi%2FTestBasic"}}

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

Я попытался переопределить это поведение в настраиваемом атрибуте AuthorizeAttribute, установив статус в ответе в методах OnAuthorization и HandleUnauthorizedRequest.

actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

Но это не сработало. Новый конвейер должен получить этот ответ позже и изменить его на тот же ответ, который я получал раньше. Создание исключения HttpException также не сработало, поскольку оно просто изменилось на статус ошибки 500.

Я тестировал решение Брока Аллена, и оно работало, когда я использовал вызов jQuery ajax. Если это не работает для вас, я предполагаю, что это потому, что вы используете angular. Запустите тест с помощью Fiddler и посмотрите, есть ли в вашем заголовке следующее.

X-Requested-With: XMLHttpRequest

Если это не так, тогда проблема. Я не знаком с angular, но если он позволяет вставлять собственные значения заголовка, добавьте это в свои запросы ajax, и он, вероятно, начнет работать.

person Kevin Junghans    schedule 22.11.2013
comment
Я думаю, что я использую System.web.http.authorizeattribute, по крайней мере, этот webapicontroller не имеет использования для system.web.mvc, и переход к определению атрибута авторизации отправляет меня на system.web.http - person Tim; 22.11.2013
comment
Привет @ kevin-junghans здесь полностью запутались. В приведенном выше примере от shiva используется атрибут авторизации mvc, который, безусловно, я не должен применять к действию webapi. Пример от Брока Аллена, похоже, не работает, либо он не думает, что это запрос ajax, когда я перехожу. - person Tim; 24.11.2013
comment
только что заметил этот ответ (думаю, stackoverflow не отправляет уведомления). Я добавил пример github, чтобы проиллюстрировать проблему, и теперь добавил ваше исправление в заголовки angular. Спасибо. Однако это кажется неправильным, что в атрибуте authorize нет свойства, которое я могу проверить, или исходная функциональность, о которой вы упомянули, больше не работает. - person Tim; 02.12.2013
comment
Использование POSTMAN и параметра заголовка X-Requested-With: XMLHttpRequest работает для меня ... спасибо - person chemitaxis; 10.05.2014
comment
Итак, что, если у вас есть то, что вы собираетесь делать в виде чистого проекта веб-API? Я работаю над проектом, созданным кем-то другим, и авторизация выполняет перенаправление, как описано здесь, но у меня есть другой проект API, который отлично работает. Должно быть что-то, заставляющее его думать, что это приложение MVC, а не приложение API, но я не могу найти, что могло его испортить. - person Derek Greer; 04.11.2015
comment
@DerekGreer - вам нужно будет предоставить более подробную информацию и код для вашей конкретной проблемы, чтобы получить любую помощь. Рекомендую вам создать еще один вопрос с подробностями, поскольку комментарии - не лучший механизм для этого. - person Kevin Junghans; 03.12.2015
comment
Моя проблема заключалась в том, что проект веб-API был настроен с использованием форм в IIS. - person Derek Greer; 03.12.2015
comment
У меня такая же проблема с обнаружением кода состояния 401. Я использую вызовы ajax и ожидаю результатов в формате JSON. Как я могу обнаружить ситуацию 401 в обещании jQuery? - person Sandun Perera; 16.03.2016

У Брока Аллена есть хорошая запись в блоге о том, как возвращать 401 для вызовов ajax при использовании аутентификации Cookie и OWIN. http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/

Поместите это в метод ConfigureAuth в файле Startup.Auth.cs:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
  AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
  LoginPath = new PathString("/Account/Login"),
  Provider = new CookieAuthenticationProvider
  {
    OnApplyRedirect = ctx =>
    {
      if (!IsAjaxRequest(ctx.Request))
      {
        ctx.Response.Redirect(ctx.RedirectUri);
      }
    }
  }
});

private static bool IsAjaxRequest(IOwinRequest request)
{
  IReadableStringCollection query = request.Query;
  if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest"))
  {
     return true;
  }
  IHeaderDictionary headers = request.Headers;
  return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest"));
}
person Olav Nybø    schedule 22.11.2013
comment
Вариант этого: если все ваши вызовы веб-API проходят определенный путь, например /api, вы можете использовать путь для определения необходимости перенаправления. Это особенно полезно, если у вас есть клиенты, использующие другие форматы, например JSON. Замените вызов IsAjaxRequest на if (!context.Request.Path.StartsWithSegments(new PathString("/api"))). - person Edward Brey; 20.12.2013
comment
Поздно на вечеринку, но этот метод - единственный, который мне подходит и кажется более точным. - person Stephen Collins; 02.09.2014
comment
Даже поздно (r) к вечеринке, но это оказалось очень полезным ... мне непостижимо, что код, сгенерированный по умолчанию, делает это так неправильно, таким разочаровывающе сложным для отладки способом. - person Nick; 21.05.2015
comment
Если вам нужно решение WebApi, ответ Маника - хорошая альтернатива высоко оцененному комментарию здесь. - person Dunc; 09.06.2015
comment
Используя C # 6, вот уменьшенная версия IsAjaxRequest: private static bool IsAjaxRequest(IOwinRequest request) { return request.Query?["X-Requested-With"] == "XMLHttpRequest" || request.Headers?["X-Requested-With"] == "XMLHttpRequest"; } - person Peter Örneholm; 03.06.2016
comment
Что касается WebAPI, вы можете посмотреть в комментариях к IsJsonRequest и интегрировать его тоже; вы также можете использовать заголовок Accept - person Mark Sowul; 02.11.2016
comment
Мое приложение запрашивает из настольного программного обеспечения в веб-API. Добавление XMLHttpRequest в мои заголовки сэкономило мне ЧАСЫ на выяснение, почему я получаю 404. Я добавил логику, чтобы определить, нужно ли мне добавлять параметр, а затем сделал это (извините, это приложение на VB): Если addXMLHttpRequest Then request. Headers.Add (X-Requested-With, XMLHttpRequest) Конец, если - person Laki Politis; 17.04.2018

Если вы добавляете asp.net WebApi на веб-сайт asp.net MVC, вы, вероятно, захотите неавторизованно отвечать на некоторые запросы. Но затем в игру вступает инфраструктура ASP.NET, и когда вы пытаетесь установить код состояния ответа на HttpStatusCode.Unauthorized, вы получите перенаправление 302 на страницу входа.

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

public void ConfigureAuth(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider()
        {
            OnApplyRedirect = ctx =>
            {
                if (!IsApiRequest(ctx.Request))
                {
                    ctx.Response.Redirect(ctx.RedirectUri);
                }
            }
        }
    });

    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}


private static bool IsApiRequest(IOwinRequest request)
{
    string apiPath = VirtualPathUtility.ToAbsolute("~/api/");
    return request.Uri.LocalPath.StartsWith(apiPath);
}
person Manik Arora    schedule 25.02.2015
comment
Я изменил дискриминант, чтобы проверить, принимают ли запросы text / html или application / xhtml в качестве ответа, если они этого не делают, я предполагаю, что это автоматический запрос клиента, такой как запрос ajax - person L.Trabacchin; 04.05.2015
comment
Я тоже предпочитаю этот подход. Единственное добавление, которое я сделал, - это преобразовать LocalPath .ToLower () в случае, если они запрашивают / API или что-то в этом роде. - person FirstDivision; 04.03.2016
comment
Большое спасибо. Это спасло мне день. :) - person Amit Kumar; 29.08.2016
comment
Кому-нибудь повезло с этим? CookieAuthenticationOptions больше не имеет свойства Provider в ядре aspnet 1.1. - person Jeremy; 18.08.2017
comment
Большое спасибо, чувак! Час искал, как этого добиться. - person Koenman; 07.09.2020

У меня такая же ситуация, когда OWIN всегда перенаправляет ответ 401 на страницу входа из WebApi. Наш веб-API поддерживает не только вызовы ajax из Angular, но и вызовы Mobile, Win Form. Следовательно, решение для проверки того, является ли запрос запросом ajax, в нашем случае не отсортировано.

Я выбрал другой подход - ввести новый ответ заголовка: Suppress-Redirect, если ответы поступают из webApi. Реализация находится в обработчике:

public class SuppressRedirectHandler : DelegatingHandler
{
    /// <summary>
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return base.SendAsync(request, cancellationToken).ContinueWith(task =>
        {
            var response = task.Result;
            response.Headers.Add("Suppress-Redirect", "True");
            return response;
        }, cancellationToken);
    }
}

И зарегистрируем этот обработчик на глобальном уровне WebApi:

config.MessageHandlers.Add(new SuppressRedirectHandler());

Итак, при запуске OWIN вы можете проверить, есть ли в заголовке ответа Suppress-Redirect:

public void Configuration(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationMode = AuthenticationMode.Active,
        AuthenticationType = DefaultApplicationTypes.ApplicationCookie,
        ExpireTimeSpan = TimeSpan.FromMinutes(48),

        LoginPath = new PathString("/NewAccount/LogOn"),

        Provider = new CookieAuthenticationProvider()
        {
            OnApplyRedirect = ctx =>
            {
                var response = ctx.Response;
                if (!IsApiResponse(ctx.Response))
                {
                    response.Redirect(ctx.RedirectUri);
                }
            }
        }
    });
}

private static bool IsApiResponse(IOwinResponse response)
{
    var responseHeader = response.Headers;

    if (responseHeader == null) 
        return false;

    if (!responseHeader.ContainsKey("Suppress-Redirect"))
        return false;

    if (!bool.TryParse(responseHeader["Suppress-Redirect"], out bool suppressRedirect))
        return false;

    return suppressRedirect;
}
person cuongle    schedule 11.06.2015
comment
Спасибо ! Наши API работали на всех платформах, кроме Xamarin / Android. Будет использовать это решение - person Jurion; 31.10.2019

В предыдущих версиях ASP.NET требовалось сделать кучу вещей, чтобы это заработало.

Хорошая новость в том, что, поскольку вы используете ASP.NET 4.5. вы можете отключить перенаправление проверки подлинности с помощью форм с помощью нового свойства HttpResponse.SuppressFormsAuthenticationRedirect.

In Global.asax:

protected void Application_EndRequest(Object sender, EventArgs e)
{
        HttpApplication context = (HttpApplication)sender;
        context.Response.SuppressFormsAuthenticationRedirect = true;
}

ИЗМЕНИТЬ: вы также можете взглянуть на в этой статье Сергея Звездина, которая предлагает более изощренный способ выполнения того, что вы пытаетесь сделать.

Соответствующие фрагменты кода и авторское повествование вставлены ниже. Оригинальный автор кода и повествования - Сергей Звездин.

Во-первых, давайте определим, является ли текущий HTTP-запрос AJAX-запросом. Если да, мы должны отключить замену HTTP 401 на HTTP 302:

public class ApplicationAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var httpContext = filterContext.HttpContext;
        var request = httpContext.Request;
        var response = httpContext.Response;

        if (request.IsAjaxRequest())
            response.SuppressFormsAuthenticationRedirect = true;

        base.HandleUnauthorizedRequest(filterContext);
    }
}

Во-вторых, давайте добавим условие: если пользователь аутентифицирован, мы отправим HTTP 403; и HTTP 401 в противном случае.

public class ApplicationAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var httpContext = filterContext.HttpContext;
        var request = httpContext.Request;
        var response = httpContext.Response;
        var user = httpContext.User;

        if (request.IsAjaxRequest())
        {
            if (user.Identity.IsAuthenticated == false)
                response.StatusCode = (int)HttpStatusCode.Unauthorized;
            else
                response.StatusCode = (int)HttpStatusCode.Forbidden;

            response.SuppressFormsAuthenticationRedirect = true;
            response.End();
        }

        base.HandleUnauthorizedRequest(filterContext);
    }
}

Отличная работа. Теперь мы должны заменить все использование стандартного AuthorizeAttribute этим новым фильтром. Это может быть неприменимо для симэ ребят, которые разбираются в коде. Но другого пути я не знаю. Если да, то давайте, пожалуйста, к комментариям.

Последнее, что нам остается сделать - добавить обработку HTTP 401/403 на стороне клиента. Мы можем использовать ajaxError в jQuery, чтобы избежать дублирования кода:

$(document).ajaxError(function (e, xhr) {
    if (xhr.status == 401)
        window.location = "/Account/Login";
    else if (xhr.status == 403)
        alert("You have no enough permissions to request this resource.");
});

Результат -

  • Если пользователь не аутентифицирован, он будет перенаправлен на страницу входа после любого AJAX-вызова.
  • Если пользователь аутентифицирован, но у него недостаточно прав, он увидит удобное для пользователя сообщение erorr.
  • Если пользователь аутентифицирован и имеет достаточно прав, то ошибок нет и HTTP-запрос будет обработан в обычном режиме.
person Shiva    schedule 22.11.2013
comment
Я использую новую структуру идентификации для аутентификации через mvc. Не помешает ли этот параметр работе входа в систему mvc, а также вызовов webapi? - person Tim; 22.11.2013
comment
когда я проверил этот пример, оказалось, что используемый атрибут авторизации - это версия MVC, а не версия WebApi. однако в версии webapi нет параметров для подавления аутентификации форм. - person Tim; 24.11.2013
comment
в моем запросе нет метода IsAjaxRequest. - person Tim; 02.12.2013
comment
Тим посмотри на это для IsAjaxRequest: brockallen.com/2013/10/27/ Если вы используете AngularJs без редактирования заголовков, у вас не будет XMLHttpRequest, и вы либо добавляете его, либо проверяете что-нибудь еще. - person Tim; 20.02.2014

Я сам использовал интеграцию с Azure Active Directory, поэтому подход с использованием CookieAuthentication промежуточного программного обеспечения для меня не сработал. Пришлось сделать следующее:

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        ...
        Notifications = new OpenIdConnectAuthenticationNotifications
        {   
            ...         
            RedirectToIdentityProvider = async context =>
            {
                if (!context.Request.Accept.Contains("html"))
                {
                    context.HandleResponse();
                }
            },
            ...
        }
    });

Если запрос исходит от самого браузера (а не от вызова AJAX, например), тогда заголовок Accept будет где-то содержать строку html. Только когда клиент примет HTML, я буду считать редирект чем-то полезным.

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

person Dave Van den Eynde    schedule 24.02.2016
comment
Это очень похоже на решение, предложенное для связанного вопроса: stackoverflow.com/questions/34997674/ - person Guillaume LaHaye; 10.08.2017

Если вы запускаете свой Web API из своего MVC проекта, вам необходимо создать собственный AuthorizeAttribute, который будет применяться к вашим API методам. Внутри IsAuthorized override вам нужно захватить текущий HttpContext, чтобы предотвратить перенаправление, например:

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        if (string.IsNullOrWhiteSpace(Thread.CurrentPrincipal.Identity.Name))
        {
            var response = HttpContext.Current.Response;
            response.SuppressFormsAuthenticationRedirect = true;
            response.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
            response.End();
        }

        return base.IsAuthorized(actionContext);
    }
person Serj Sagan    schedule 03.07.2015

У меня также было приложение MVC5 (System.Web) с WebApi (с использованием OWIN), и я просто хотел предотвратить изменение 401 ответа от WebApi на 302 ответа.

Что сработало для меня, так это создать настроенную версию WebApi AuthorizeAttribute следующим образом:

public class MyAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        base.HandleUnauthorizedRequest(actionContext);
        HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;
    }
}

И использовать его вместо стандартного атрибута авторизации WebApi. Я использовал стандартный MVC AuthorizeAttribute, чтобы поведение MVC оставалось неизменным.

person Jono Job    schedule 03.06.2016
comment
Работает, но теперь у меня проблема, что клиент получает статус -1 вместо 401 - person Sebastián Rojas; 31.07.2016
comment
@ SebastiánRojas Я не уверен, что могло быть причиной этого - установка флага SuppressFormsAuthenticationRedirect заставила его просто вернуть существующий 401 для меня. - person Jono Job; 01.08.2016

Просто установите следующий пакет NeGet

Инсталляционный пакет Microsoft.AspNet.WebApi.Owin

Напишите следующий код в файле WebApiConfig.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //Web API configuration and services
        //Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
    }
}
person Community    schedule 23.08.2017
comment
Все, что мне нужно было сделать, это добавить этот фильтр, и он работает config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); иначе User.Identity.IsAuthenticated всегда false - person Ricardo Saracino; 15.12.2019

если вы хотите поймать Content-Type == application / json, вы можете использовать этот код:

private static bool IsAjaxRequest(IOwinRequest request)
    {
        IReadableStringCollection queryXML = request.Query;
        if ((queryXML != null) && (queryXML["X-Requested-With"] == "XMLHttpRequest"))
        {
            return true;
        }

        IReadableStringCollection queryJSON = request.Query;
        if ((queryJSON != null) && (queryJSON["Content-Type"] == "application/json"))
        {
            return true;
        }

        IHeaderDictionary headersXML = request.Headers;
        var isAjax = ((headersXML != null) && (headersXML["X-Requested-With"] == "XMLHttpRequest"));

        IHeaderDictionary headers = request.Headers;
        var isJson = ((headers != null) && (headers["Content-Type"] == "application/json"));

        return isAjax || isJson;

    }

С уважением!!

person chemitaxis    schedule 10.05.2014

Мне было трудно получить как код состояния, так и текстовый ответ, работающие в методах OnAuthorization / HandleUnauthorizedRequest. Для меня это оказалось лучшим решением:

    actionContext.Response = new HttpResponseMessage()
    {
        StatusCode = HttpStatusCode.Forbidden,
        Content = new StringContent(unauthorizedMessage)
    };
person PutoTropical    schedule 10.08.2017

Смешивание MVC и WebAPI, если запрос неавторизован, он также перенаправит на страницу входа в систему даже в запросе WebAPI. Для этого мы можем добавить ниже код для отправки ответа мобильному приложению.

protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
    var httpContext = HttpContext.Current;
    if (httpContext == null)
    {
        base.HandleUnauthorizedRequest(actionContext);
        return;
    }

    actionContext.Response = httpContext.User.Identity.IsAuthenticated == false ?
        actionContext.Request.CreateErrorResponse(
      System.Net.HttpStatusCode.Unauthorized, "Unauthorized") :
       actionContext.Request.CreateErrorResponse(
      System.Net.HttpStatusCode.Forbidden, "Forbidden");

    httpContext.Response.SuppressFormsAuthenticationRedirect = true;
    httpContext.Response.End();
}
person Avid Programmer    schedule 08.09.2019

После долгих попыток избежать перенаправления на страницу входа я понял, что на самом деле это вполне подходит для атрибута Authorize. Он говорит: «Иди и получи авторизацию». Вместо того, чтобы использовать вызовы Api, которые не авторизованы, я просто хотел не раскрывать какую-либо информацию хакерам. Этой цели было легче достичь напрямую, добавив новый атрибут, производный от Authorize, который вместо этого скрывает контент как ошибку 404:

public class HideFromAnonymousUsersAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
         actionContext.Response = ActionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "Access Restricted");
    }
}
person user3879365    schedule 25.10.2014

Спасибо ребята!

В моем случае я объединил cuongle и Шива получил что-то вроде этого:

В обработчике OnException () контроллера для исключений API:

filterContext.ExceptionHandled = true;
//...
var response = filterContext.HttpContext.Response;
response.Headers.Add("Suppress-Redirect", "true");
response.SuppressFormsAuthenticationRedirect = true;

В коде конфигурации запуска приложения:

app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider {
            OnValidateIdentity = ctx => {
                return validateFn.Invoke(ctx);
            },
            OnApplyRedirect = ctx =>
            {
                bool enableRedir = true;
                if (ctx.Response != null)
                {
                    string respType = ctx.Response.ContentType;
                    string suppress = ctx.Response.Headers["Suppress-Redirect"];
                    if (respType != null)
                    {
                        Regex rx = new Regex("^application\\/json(;(.*))?$",
                            RegexOptions.IgnoreCase);
                        if (rx.IsMatch(respType))
                        {
                            enableRedir = false;
                        }  
                    }
                    if ((!String.IsNullOrEmpty(suppress)) && (Boolean.Parse(suppress)))
                    {
                        enableRedir = false;
                    }
                }
                if (enableRedir)
                {
                    ctx.Response.Redirect(ctx.RedirectUri);
                }
            }
        }
    });
person Chakrit W    schedule 19.12.2018
comment
Я думал, что X-Requested-With: XMLHttpRequest вводится для этого конкретного сценария. При выполнении вызовов ajx просто добавьте это в свой заголовок, и сервер должен вернуть правильный ответ. По крайней мере, это обрабатывается в abp.io - person Santosh Karanam; 24.03.2021

В MVC 5 с Dot Net Framework 4.5.2 мы получаем "application / json, plaint text .." под заголовком "Accept". Было бы неплохо использовать следующее:

isJson = headers["Content-Type"] == "application/json" || headers["Accept"].IndexOf("application/json", System.StringComparison.CurrentCultureIgnoreCase) >= 0;
person Imran Javed    schedule 11.03.2015