401 code de réponse pour les requêtes json avec ASP.NET MVC


35

Comment désactiver le traitement standard ASP.NET du code de réponse 401 (redirection vers la page de connexion) pour les requêtes AJAX/JSON?

Pour les pages Web c'est bon, mais pour AJAX, je dois obtenir le code d'erreur 401 au lieu de 302/200 pour la page de connexion.

Mise à jour: Il existe plusieurs solutions de Phil Haack, PM de ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx

18

le runtime ASP.NET est développé de sorte qu'il sera toujours rediriger l'utilisateur si le HttpResponse.StatusCode est réglé sur 401, mais seulement si la section <authentication /> du web.config se trouve.

Retrait de la section d'authentification vous demandera pour implémenter la redirection vers la page de connexion dans votre attribut, mais cette ne devrait pas être un gros problème.

  0

La meilleure façon de mettre en œuvre votre propre redirection est de sous-classer AuthorizeAttribute, et lorsqu'il n'est pas autorisé, définissez le résultat à un RedirectResult au lieu de HttpUnauthorizedResult. 07 janv.. 102010-01-07 15:44:45

+2

Oui, mais dans ce cas, l'OP voudrait envoyer le code HTTP 401, mais pas de redirection (pour fonctionner correctement avec JSON). 08 janv.. 102010-01-08 20:34:45

  0

Fonctionne pour moi - bien que j'ai configuré le paramètre comme <authentication mode = "None" /> au lieu de supprimer complètement l'attribut. 15 juin. 132013-06-15 03:20:54

+3

Um - sauf que j'utilise l'authentification par formulaires dans les contrôleurs MVC, donc cela ne fonctionne pas pour moi. Besoin d'une solution d'authentification 404 && Forms, pas non plus ||. 18 juin. 132013-06-18 04:18:48

+1

quel est le correctif si vous souhaitez utiliser l'authentification par formulaire et avoir une redirection 401 personnalisée? 29 août. 132013-08-29 16:59:01

+2

@DevDave - Voir ma réponse. 29 août. 132013-08-29 22:52:34


1

Vous pouvez choisir de créer une coutume FilterAttribute implémentant l'interface IAuthorizationFilter.

Dans cet attribut, vous ajoutez une logique pour déterminer si la requête est supposée renvoyer JSON. Si c'est le cas, vous pouvez renvoyer un résultat JSON vide (ou faire ce que vous voulez), étant donné que l'utilisateur n'est pas connecté. Pour les autres réponses, vous devez simplement rediriger l'utilisateur comme toujours.

Encore mieux, vous pouvez simplement remplacer le OnAuthorization de la classe AuthorizeAttribute afin de ne pas avoir à réinventer la roue. Ajouter la logique je l'ai mentionné ci-dessus et l'interception si le filterContext.Cancel est vrai (le filterContext.Result sera réglé sur une instance de la

classe HttpUnauthorizedResult. En savoir plus sur "Filters in ASP.NET MVC CodePlex Preview 4" sur le blog Phil Haacks. Il applique également le dernier aperçu.

  0

Mais je n'arrive toujours pas à obtenir le code d'état de réponse 401 pour la requête AJAX. Même si je configure une réponse dans le filtre d'autorisation. Depuis l'infrastructure ASP.NET qui interceptent la réponse 401 et la redirection vers la page de connexion se trouve sur ASP.NET MVC. Laisser savoir que l'utilisateur n'est pas connecté par résultat JSON vide n'est pas très juste ... 24 sept.. 082008-09-24 15:04:09

  0

Je ne comprenais pas exactement ce que vous aviez en tête jusqu'à maintenant. J'ajoute une nouvelle réponse qui résoudra votre problème. 24 sept.. 082008-09-24 22:24:04

+1

Comment avez-vous réussi à poster deux réponses? :) 30 août. 132013-08-30 09:13:50


2

Vous pouvez également utiliser le Global.asax pour interrompre ce processus avec quelque chose comme ceci:

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

Je l'ai fait, sauf que j'ai vérifié pour le 302 et X-Requested-With dans la réponse de @troethom ci-dessus. 09 sept.. 102010-09-09 18:35:57


24

Dans ASP.NET classique, vous obtenez un code de réponse 401 http lorsque vous appelez un WebMethod avec l'Ajax. J'espère qu'ils vont le changer dans les futures versions d'ASP.NET MVC. En ce moment j'utilise ce 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

Ceci est une très bonne solution d'arrêt si vous avez besoin de quelque chose de rapide qui fonctionne. Sinon, j'essaierais d'implémenter la réponse @troethom. 07 janv.. 102010-01-07 15:44:04


8

Je voulais l'authentification des deux formulaires et renvoyer un 401 pour les demandes Ajax qui n'étaient pas authentifiées. En fin de compte, j'ai créé un AuthorizeAttribute personnalisé et décoré les méthodes du contrôleur. (Ceci est le .Net 4.5)

//web.config

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

// contrôleur

[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

et si je veux utiliser les formulaires standard autorisent les redirections lorsqu'un utilisateur n'est pas connecté, mais aussi d'invoquer des redirections personnalisées 401 quand un utilisateur n'a pas la permission pertinente, des idées? 30 août. 132013-08-30 11:41:59

  0

Vous obtiendrez des redirections de formulaires normaux sur les méthodes qui n'ont pas AuthorizeAttribute. Vous pouvez également étendre cet attribut en fournissant la clause "else" de if (! FilterContext.IsAuthenticated) dans laquelle vous vérifieriez les permissions et ensuite vous installeriez la redirection vous-même. 30 août. 132013-08-30 18:42:13


2

Je ne vois pas ce que nous devons modifier le mode d'authentification ou la balise d'authentification comme le dit la réponse actuelle.Suite à l'idée de @TimothyLeeRussell (merci d'ailleurs), j'ai créé un attribut Authorize personnalisé (le problème avec celui de @TimothyLeeRussell est qu'une exception est throw parce qu'il essaie de changer le filterContext.Result et qui génère HttpException, et en supprimant cette partie, à part le filterContext.HttpContext.Response.StatusCode = 401, le code de réponse était toujours 200 OK). Donc j'ai finalement résolu le problème en mettant fin à la réponse après les changements.

[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 propriété SuppressFormsAuthenticationRedirect était exactement ce que je recherchais. 14 juil.. 152015-07-14 12:04:02


1

Vous pouvez appeler cette méthode dans votre action,

HttpContext.Response.End(); 

Exemple

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

De MSDN: La méthode finale, le serveur Web pour arrêter le traitement du script et retourner le courant résultat. Le contenu restant du fichier n'est pas traité.