10

W środowisku ASP.NET moduł FormsAuthenticationModule przechwytuje każdy HTTP 401 i zwraca przekierowanie HTTP 302 do strony logowania. To jest problem dla AJAX, ponieważ pytasz o jsona i uzyskujesz stronę logowania w html, ale kod statusu to HTTP 200.Zapobieganie formularzom uwierzytelniania Moduł przechwytywania odpowiedzi interfejsu API ASP.NET

Jaki jest sposób uniknięcia tego przechwycenia w ASP.NET Web API?

w ASP.NET MVC4 jest bardzo łatwo zapobiec przechwyceniu przez kończąc wyraźnie połączenia:

public class MyMvcAuthFilter:AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest() && !filterContext.IsChildAction) 
     { 
      filterContext.Result = new HttpStatusCodeResult(401); 
      filterContext.HttpContext.Response.StatusCode = 401; 
      filterContext.HttpContext.Response.SuppressContent = true; 
      filterContext.HttpContext.Response.End(); 
     } 
     else 
      base.HandleUnauthorizedRequest(filterContext); 
    } 
} 

ale w ASP.NET Web API nie mogę zakończyć połączenie jawnie, więc nawet gdy używam tego kodeks FormsAuthenticationModule przechwytuje odpowiedź i wysyła przekierowanie do strony logowania:

public class MyWebApiAuth: AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     if(actionContext.Request.Headers.Any(h=>h.Key.Equals("X-Requested-With",StringComparison.OrdinalIgnoreCase))) 
     { 
      var xhr = actionContext.Request.Headers.Single(h => h.Key.Equals("X-Requested-With", StringComparison.OrdinalIgnoreCase)).Value.First(); 

      if (xhr.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase)) 
      { 
       // this does not work either 
       //throw new HttpResponseException(HttpStatusCode.Unauthorized); 

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

     base.HandleUnauthorizedRequest(actionContext); 
    } 
} 

Jaki jest sposób na uniknięcie tego problemu w ASP.NET Web API? Przyjrzałem się i nie mogłem znaleźć sposobu na zrobienie tego.

Pozdrawiam.

PS: Nie mogę uwierzyć, że to jest 2012, a ten problem nadal trwa.

+1

dla nikogo patrząc, spróbuj tego: http://blog.craigtp.co.uk/post/OWIN-Hosted-Web-API-in-an-MVC-Project – Sentinel

+0

Link opublikowany przez @Sentinel rozwiązuje mój problem .... dzięki! –

Odpowiedz

4

Uwagi do wydania dla MVC 4 RC sugerują, że zostało to rozwiązane od czasu wersji beta - z której korzystasz?

http://www.asp.net/whitepapers/mvc4-release-notes Nieautoryzowane rozpatrzonych przez ASP.NET Web API zwrotu 401 Unauthroized: Nieautoryzowane rozpatrzonych przez ASP.NET Web API teraz powrócić do standardowego 401. zamiast przekierowania agenta użytkownika do formularza logowania tak, że odpowiedź może być obsługiwany przez klienta Ajax.

Patrząc w kod źródłowy MVC wydaje się być funkcjonalność dodana przez SuppressFormsAuthRedirectModule.cs

http://aspnetwebstack.codeplex.com/SourceControl/network/forks/BradWilson/AspNetWebStack/changeset/changes/ae1164a2e339#src%2fSystem.Web.Http.WebHost%2fHttpControllerHandler.cs.

internal static bool GetEnabled(NameValueCollection appSettings) 
    { 
      // anything but "false" will return true, which is the default behavior 

Więc wygląda to ta jest domyślnie włączona i RC powinno rozwiązać problem bez heroizmu ... jako punkt boku wygląda jak można wyłączyć za pomocą nowego modułu AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815:

<appSettings> 
    <Add Key = "webapi:EnableSuppressRedirect" value = "false" /> 
</appSettings> 

Edit (przykład i wyjaśnienie)

mam teraz tworzone przykład tego podejścia GitHub. Nowe tłumienie przekierowania wymaga użycia dwóch poprawnych atrybutów "Autoryzuj"; MVC Web [System.Web.Mvc.Authorize] i Web API [System.Web.Http.Authorize] w kontrolerach AND/OR w globalnych filtrach Link.

Ten przykład przedstawia jednak ograniczenie podejścia. Wygląda na to, że węzły "autoryzacji" w pliku web.config zawsze będą miały pierwszeństwo przed trasami MVC, np. config tak zastąpi swoje zasady i nadal przekierowanie do logowania:

<system.web> 
    <authentication mode="Forms"> 
    </authentication> 
    <authorization> 
     <deny users="?"/> //will deny anonymous users to all routes including WebApi 
    </authorization> 
</system.web> 

Niestety otwarcia to dla niektórych trasach url element Lokalizacja nie wydaje się do pracy i rozmowy WebAPI nadal będą przechwytywane i przekierowywane do Zaloguj Się.

Solutions

Dla aplikacji MVC mam po prostu sugerują usuwając config z web.config i wystaje z filtrami globalne i atrybutów w kodzie.

Jeśli musisz użyć węzłów autoryzacji w Web.Config dla MVC lub mieć aplikację Hybrid ASP.NET i WebApi, to @PilotBob - w komentarzach poniżej - odkrył, że pod foldery i wiele Web.Config można użyć do zjedz tort i zjedz go.

+0

Używam wersji beta, ponieważ w zeszłym tygodniu próbowałem uzyskać najnowszą wersję, a DependencyResolver nie działało zgodnie z oczekiwaniami, więc Ninject MVC nie działało, próbowałem kilka obejść zaproponowanych na ten średni czas, ale nie działało . Czy wiesz coś na ten temat? Stukrotne dzięki. – vtortola

+1

@NullOrEmpty Oh OK. Jestem na RC z Ninject (przeniesiony z Autofac, tak jak miałem problemy we wczesnych dniach RC). Ten link opisuje podejście identyczne do mojego i powinien działać dobrze http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/ –

+0

Wielkie dzięki! Spróbuję później. – vtortola

2

udało mi się obejść odmówić anonimowego ustawienia w pliku web.config przez ustawienie następującą właściwość:

Request.RequestContext.HttpContext.SkipAuthorization = true;

Robię to po sprawdzeniu obiektu Request w metodzie Application_BeginRequest w pliku Global.asax.cs, takich jak właściwość RawURL i inne informacje nagłówkowe, aby upewnić się, że żądanie uzyskuje dostęp do obszaru, który chcę umożliwić anonimowy dostęp do . Nadal przeprowadzam uwierzytelnianie/autoryzację po wywołaniu akcji API.

5

W przypadku gdy ktoś jest zainteresowany w kontaktach z tej samej kwestii w ASP.NET MVC aplikacji za pomocą atrybutu zezwolić na:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
public class Authorize2Attribute : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAuthenticated) 
     { 
      filterContext.Result = new HttpStatusCodeResult((int) HttpStatusCode.Forbidden); 
     } 
     else 
     { 
      if (filterContext.HttpContext.Request.IsAjaxRequest()) 
      { 
       filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 
      } 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
    } 
} 

Ta przeglądarka sposób prawidłowo rozróżnia zabronione i nieautoryzowanych żądań ..