401 codice di risposta per richieste json con ASP.NET MVC


35

Come disabilitare la gestione ASP.NET standard del codice di risposta 401 (reindirizzamento alla pagina di accesso) per le richieste AJAX/JSON?

Per le pagine Web va bene, ma per AJAX ho bisogno di ottenere il codice di errore 401 corretto invece del 302/200 bello per la pagina di accesso.

Aggiornamento: Ci sono diverse soluzioni da Phil Haack, PM di ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx

18

il runtime ASP.NET è sviluppato in modo che lo sarà sempre reindirizzare l'utente se il HttpResponse.StatusCode è impostato su 401, ma solo se si trova la sezione <authentication /> del web.config.

Rimozione della sezione di autenticazione si richiede all'utente per implementare il reindirizzamento alla pagina di accesso nel tuo attributo, ma questo non dovrebbe essere un grosso problema.

  0

Il modo migliore per implementare il proprio reindirizzamento è sottoclasse AuthorizeAttribute e, quando non autorizzato, impostare il risultato su RedirectResult anziché su HttpUnauthorizedResult. 07 gen. 102010-01-07 15:44:45

+2

Sì, ma in questo caso l'OP vorrebbe inviare il codice HTTP 401, ma non il reindirizzamento (per funzionare correttamente con JSON). 08 gen. 102010-01-08 20:34:45

  0

Funziona per me, anche se ho configurato l'impostazione come <authentication mode = "None" /> invece di rimuovere completamente l'attributo. 15 giu. 132013-06-15 03:20:54

+3

Um - eccetto che sto usando l'autenticazione basata sui moduli nei controller MVC, quindi in realtà questo non funziona per me. Hai bisogno di una soluzione di autenticazione basata su form 404 && e non di ||. 18 giu. 132013-06-18 04:18:48

+1

qual è la correzione se si desidera utilizzare l'autenticazione basata su form e disporre di un reindirizzamento 401 personalizzato? 29 ago. 132013-08-29 16:59:01

+2

@DevDave - Vedi la mia risposta. 29 ago. 132013-08-29 22:52:34


1

Si potrebbe scegliere di creare un costume FilterAttribute che implementa l'interfaccia IAuthorizationFilter.

In questo attributo si aggiunge la logica per determinare se la richiesta deve restituire JSON. In tal caso, puoi restituire un risultato JSON vuoto (o fare quello che vuoi) dato che l'utente non ha effettuato l'accesso. Per altre risposte, dovrai semplicemente reindirizzare l'utente come sempre.

Ancora meglio, è possibile ignorare lo OnAuthorization della classe AuthorizeAttribute in modo da non dover reinventare la ruota. Aggiungere la logica che ho citato sopra e intercetta se il filterContext.Cancel è vero (il filterContext.Result sarà impostato a un'istanza della classe HttpUnauthorizedResult.

Per saperne di più "Filters in ASP.NET MVC CodePlex Preview 4" su Phil Haacks blog. Si applica anche alla più recente anteprima.

  0

Ma non riesco ancora a ottenere il codice di stato di risposta 401 per la richiesta AJAX. Anche se imposto la risposta nel filtro di Autorizzazione. Poiché l'infrastruttura ASP.NET rileva la risposta 401 e il reindirizzamento alla pagina di accesso si trova su ASP.NET MVC. Lasciando sapere che l'utente non è registrato da vuoto JSON risultato non è molto giusto ... 24 set. 082008-09-24 15:04:09

  0

Non ho capito esattamente quello che avevi in ​​mente fino ad ora. Sto aggiungendo una nuova risposta che risolverà il tuo problema. 24 set. 082008-09-24 22:24:04

+1

come sei riuscito a postare due risposte? :) 30 ago. 132013-08-30 09:13:50


2

Si potrebbe anche usare il Global.asax per interrompere questo processo con qualcosa di simile:

protected void Application_PreSendRequestHeaders(object sender, EventArgs e) { 
     if (Response.StatusCode == 401) { 
      Response.Clear(); 
      Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx")); 
      return; 
     } 
    } 
+1

Ho fatto questo, tranne che ho controllato il 302 e X-Requested-With nella risposta di @troethom sopra. 09 set. 102010-09-09 18:35:57


24

In ASP.NET classico si ottiene un codice di risposta 401 HTTP quando si chiama un WebMethod con l'Ajax. Spero che lo cambieranno nelle versioni future di ASP.NET MVC. In questo momento sto usando questo hack:

protected void Application_EndRequest() 
{ 
    if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest") 
    { 
     Context.Response.Clear(); 
     Context.Response.StatusCode = 401; 
    } 
} 
  0

Questa è una soluzione stop-gap davvero buona se hai bisogno di qualcosa di veloce che funzioni. Altrimenti proverò a implementare la risposta @troethom. 07 gen. 102010-01-07 15:44:04


8

volevo sia l'autenticazione Forms e per restituire un 401 per le richieste Ajax che non sono stati autenticati.

Alla fine, ho creato un AuthorizeAttribute personalizzato e decorato i metodi del controller. (Questo è il Net 4.5)

//web.config

<authentication mode="Forms"> 
</authentication> 

// regolatore

[Authorize(Roles = "Administrator,User"), Response302to401] 
[AcceptVerbs("Get")] 
public async Task<JsonResult> GetDocuments() 
{ 
    string requestUri = User.Identity.Name.ToLower() + "/document"; 
    RequestKeyHttpClient<IEnumerable<DocumentModel>, string> client = 
     new RequestKeyHttpClient<IEnumerable<DocumentModel>, string>(requestUri); 

    var documents = await client.GetManyAsync<IEnumerable<DocumentModel>>(); 

    return Json(documents, JsonRequestBehavior.AllowGet); 
} 

// AuthorizeAttribute

public class Response302to401 : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
     { 
      if (filterContext.HttpContext.Request.IsAjaxRequest()) 
      { 
       filterContext.Result = new JsonResult 
       { 
        Data = new { Message = "Your session has died a terrible and gruesome death" }, 
        JsonRequestBehavior = JsonRequestBehavior.AllowGet 
       }; 
       filterContext.HttpContext.Response.StatusCode = 401; 
       filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate"; 
       filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 
      } 
     } 
     //base.HandleUnauthorizedRequest(filterContext); 
    } 
} 
  0

E se volessi utilizzare i moduli standard autorizzare i reindirizzamenti quando un utente non ha effettuato l'accesso, ma anche invocare reindirizzamenti personalizzati 401 quando un utente non dispone dell'autorizzazione pertinente, delle idee? 30 ago. 132013-08-30 11:41:59

  0

Otterrete i normali reindirizzamenti dei moduli su metodi che non dispongono di questo AuthorizeAttribute. Potresti anche solo espandere questo attributo fornendo la clausola "else" di if (! FilterContext.IsAuthenticated) in cui verificherai i permessi e quindi imposterai il reindirizzamento. 30 ago. 132013-08-30 18:42:13


2

non vedo che cosa dobbiamo modificare la modalità di autenticazione o il tag di autenticazione come dice la risposta corrente.

Seguendo l'idea di @TimothyLeeRussell (grazie tra l'altro), ho creato un attributo Authorize personalizzato (il problema con quello di @TimothyLeeRussell è che un'eccezione viene lanciata perché tenta di cambiare il filtroContext.Result che genera una HttpException, e rimuovendo quella parte, oltre a filterContext.HttpContext.Response.StatusCode = 401, il codice di risposta era sempre 200 OK). Quindi alla fine ho risolto il problema terminando la risposta dopo le modifiche.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 
public class BetterAuthorize : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest()) 
     { 
      //Set the response status code to 500 
      filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
      filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate"; 
      filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 

      filterContext.HttpContext.Response.End(); 
     } 
     else 
      base.HandleUnauthorizedRequest(filterContext); 
    } 
} 
+1

la proprietà SuppressFormsAuthenticationRedirect era esattamente quello che stavo cercando. 14 lug. 152015-07-14 12:04:02


1

È possibile chiamare questo metodo all'interno della vostra azione,

HttpContext.Response.End(); 

Esempio

public async Task<JsonResult> Return401() 
{ 
    HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
    HttpContext.Response.End(); 
    return Json("Unauthorized", JsonRequestBehavior.AllowGet); 
} 

Da MSDN: Il metodo finale fa sì che il server Web per interrompere l'elaborazione dello script e tornare la corrente risultato. Il contenuto rimanente del file non viene elaborato.