10

In ASP.NET il FormsAuthenticationModule intercetta qualsiasi HTTP 401 e restituisce un reindirizzamento HTTP 302 alla pagina di accesso. Questo è un problema per AJAX, dal momento che chiedi di JSON e ottieni la pagina di login in html, ma il codice di stato è HTTP 200.Prevent FormsAuthenticationModule di intercettazione di risposte API Web ASP.NET

Qual è il modo di evitare questa intercettazione in API Web ASP.NET?

In ASP.NET MVC4 è molto facile per evitare che questa intercettazione terminando esplicitamente la connessione:

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); 
    } 
} 

Ma in ASP.NET Web API non riesco a terminare la connessione in modo esplicito, quindi, anche quando uso questo codice FormsAuthenticationModule intercetta la risposta e invia un reindirizzamento alla pagina di login:

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); 
    } 
} 

Qual è il modo di evitare questo comportamento in ASP.NET Web API? Ho dato un'occhiata e non ho trovato il modo di farlo.

Saluti.

PS: Non posso credere che questo sia il 2012 e questo problema è ancora attivo.

+1

Per chiunque altro cercando, prova questo: http://blog.craigtp.co.uk/post/OWIN-Hosted-Web-API-in-an-MVC-Project – Sentinel

+0

Il link pubblicato da @Sentinel risolve il mio problema .... grazie! –

risposta

4

Le note di rilascio per MVC 4 RC implicano che questo è stato risolto dal momento che la Beta - che stai utilizzando?

richieste

http://www.asp.net/whitepapers/mvc4-release-notes non autorizzate gestite da ASP.NET ritorno API Web 401 Unauthroized: le richieste non autorizzate gestite da ASP.NET Web API ora restituire una risposta 401 non autorizzato standard invece di reindirizzare il programma utente di un form di login in modo che la risposta può essere gestito da un client Ajax.

Guardando il codice sorgente per MVC Sembra che ci sia una funzionalità aggiunte tramite 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 

in modo che appaia questa questa è abilitata di default e RC dovrebbe risolvere il problema, senza eroismi ... come punto di lato sembra che è possibile disabilitare questo nuovo modulo utilizzando AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815:

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

Edit (esempio e chiarimenti)

ora ho creato un esempio di questo approccio su GitHub. La nuova soppressione di reindirizzamento richiede l'utilizzo dei due attributi "Autorizza" corretti; MVC Web [System.Web.Mvc.Authorize] e Web API [System.Web.Http.Authorize] nei controller AND/OR nei filtri globali Link.

Questo esempio tuttavia traccia una limitazione dell'approccio. Sembra che i nodi di "autorizzazione" nel web.config abbiano sempre la priorità su percorsi MVC, ad es. config come questo sovrascriverà le regole e ancora reindirizzare al login:

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

Purtroppo l'apertura di questo per alcune rotte URL utilizzando l'elemento di posizione non sembra funzionare e le chiamate WebAPI continuerà ad essere intercettati e reindirizzato a accesso.

Solutions

Per le applicazioni MVC Sto semplicemente suggerisco di rimuovere la configurazione dal web.config e attaccare con filtri globali e attributi nel codice.

Se è necessario utilizzare i nodi di autorizzazione in Web.Config per MVC o disporre di un'applicazione ibrida ASP.NET e WebApi, allora @PilotBob - nei commenti di seguito - ha rilevato che le sottocartelle e più Web.Config possono essere utilizzate per prendi la tua torta e mangiala

+0

Uso la versione beta perché la settimana scorsa ho cercato di ottenere l'ultima versione e DependencyResolver non funzionava come previsto, quindi Ninject MVC non ha funzionato, ho provato un paio di soluzioni alternative per il tempo medio, ma non ha funzionato . Ne sai qualcosa? Grazie mille. – vtortola

+1

@NullOrEmpty Oh OK. Sono su RC con Ninject (spostato da Autofac perché avevo problemi nei primi giorni della RC). Questo collegamento descrive un approccio identico al mio e dovrebbe funzionare bene http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/ –

+0

Great thanks! Farò un tentativo dopo. – vtortola

2

sono stato in grado di aggirare l'impostazione anonima negare nel web.config impostando la seguente proprietà:

Request.RequestContext.HttpContext.SkipAuthorization = true;

Lo faccio dopo alcuni controlli sull'oggetto Request nel metodo Application_BeginRequest in Global.asax.cs, come la proprietà RawURL e altre informazioni di intestazione per assicurarmi che la richiesta stia accedendo a un'area a cui voglio consentire l'accesso anonimo . Eseguo ancora l'autenticazione/l'autorizzazione dopo aver chiamato l'azione dell'API.

5

Nel caso in cui qualcuno è interessato a che fare con lo stesso problema in ASP.NET MVC applicazione utilizzando l'attributo Autorizza:

[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); 
     } 
    } 
} 

Questo browser modo distingue correttamente tra le richieste non autorizzate proibiti e ..