186 votes

appel non autorisé webapi retour page de connexion plutôt que 401

Comment puis-je configurer mon mvc/webapi projet, de sorte qu'une webapi méthode est appelée à partir d'un rasoir vue ne renvoie pas le loginpage lors de son non autorisée?

Ses un MVC5 application qui a également WebApi contrôleurs pour les appels via javascript.

Les deux méthodes ci-dessous

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

sont appelées par la suite angulaire de code:

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

Donc, je suis ne suis pas connecté et que la première méthode renvoie les données. la deuxième méthode retourne (dans la réussite de la fonction) de données qui contient l'équivalent d'une page de connexion. c'est à dire ce que vous pourriez obtenir dans mvc si vous avez demandé une action de contrôleur qui a été estampillé avec [Autoriser] et vous n'étiez pas connecté.

Je veux le retour d'un 401 non autorisé, de sorte que je peux afficher des données différentes pour les utilisateurs en fonction de si ils sont connectés ou non. Idéalement, si l'utilisateur est connecté, je veux être en mesure d'accéder au Contrôleur de la propriété de l'Utilisateur afin que je puisse revenir de données spécifiques à ce Membre.

Mise à JOUR: étant donné qu'aucune des suggestions ci-dessous semblent plus travailler (changements pour l'Identité ou la WebAPI) ive créé un raw exemple sur github qui devrait illustrer le problème.

128voto

Olav Nybø Points 4054

Brock Allen a un blog sympa sur comment retourner 401 pour les appels ajax lors de l’utilisation de Cookie d’authentification et OWIN. http://brockallen.com/2013/10/27/using-cookie-Authentication-middleware-with-Web-API-and-401-Response-codes/

Mettre cela dans la méthode ConfigureAuth dans le fichier Startup.Auth.cs :

79voto

Kevin Junghans Points 10012

Il y a deux AuthorizeAttribute implémentations et vous devez vous assurer que vous faites référence à la correcte pour le Web API. Il y a du Système.Web.Http.AuthorizeAttribute qui est utilisé pour le Web API, et du Système.Web.Mvc.AuthorizeAttribute qui est utilisé pour les contrôleurs avec vue. Http.AuthorizeAttribute retournera une erreur 401 si l'autorisation échoue et Mvc.AuthorizeAttribute vous redirigera vers la page de connexion.

Mise à jour 11/26/2013

Donc il semble que les choses ont radicalement changé avec MVC 5 comme Brock Allen a souligné dans son article. Je suppose que le OWIN pipeline prend le dessus et introduit quelques nouveaux comportements. Maintenant, lorsque l'utilisateur n'est pas autorisé d'un statut de 200 est retourné avec les informations suivantes dans l'en-tête HTTP.

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

Vous pouvez changer votre logique sur le côté client de vérifier cette information dans l'en-tête pour savoir comment gérer cela, au lieu de chercher une 401 statut de l'erreur de la branche.

J'ai essayé de remplacer ce comportement personnalisé dans un AuthorizeAttribute en définissant le statut de la réponse à la OnAuthorization et HandleUnauthorizedRequest méthodes.

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

Mais cela ne fonctionne pas. Le nouveau gazoduc doit saisir cette réponse plus tard et de le modifier à la même réponse j'avais avant. Jetant un HttpException n'a pas fonctionné comme il est changé en une 500 de statut d'erreur.

J'ai testé Brock Allen solution et il a fait un travail quand j'ai été en utilisant un appel ajax jQuery. Si elle ne fonctionne pas pour vous je suppose que c'est parce que vous êtes à l'aide angulaire. Exécutez votre test avec un violon et de voir si la suite est dans votre tête.

X-Requested-With: XMLHttpRequest

Si elle n'est pas alors que c'est le problème. Je ne suis pas familier avec anguleux, mais si il vous permet d'insérer vos propres valeurs d'en-tête, puis les ajouter à vos requêtes ajax et il sera probablement commencer à travailler.

17voto

Shiva Points 4745

Dans les versions précédentes de ASP.NET, vous avez eu à faire tout un tas de choses pour obtenir ce travail.

La bonne nouvelle, c'est que depuis que vous êtes en utilisant ASP.NET 4.5. vous pouvez désactiver l'authentification par formulaires de redirection à l'aide de la nouvelle HttpResponse.SuppressFormsAuthenticationRedirect de la propriété.

En Global.asax:

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

EDIT: Vous pouvez également jeter un oeil à cet article par Sergey Zwezdin qui a une plus raffinée de l'accomplissement de ce que vous essayez de faire.

Extraits de code pertinentes et auteur de la narration collé ci-dessous. Auteur Original du code et de la narration -- Sergey Zwezdin.

D'abord – nous allons déterminer si les HTTP-request est AJAX-demande. Si oui, nous devons désactiver le remplacement de HTTP 401 avec 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);
    }
}

La deuxième, nous allons ajouter une condition: si l'authentification de l'utilisateur, puis nous vous enverrons HTTP 403; et HTTP 401 autrement.

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

Bien fait. Maintenant, nous devons remplacer tout de l'usage de la norme AuthorizeAttribute avec ce nouveau filtre. Il peut ne pas être applicable pour sime les gars, qui est esthète de code. Mais je ne connais pas d'autre moyen. Si vous avez, laissez-y des commentaires, s'il vous plaît.

La dernière, ce que nous devrions faire à ajouter HTTP 401/403 la manipulation sur le côté client. Nous pouvons utiliser ajaxError à jQuery pour éviter la duplication de code:

$(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.");
});

Le résultat –

  • Si l'utilisateur n'est pas authentifié, alors, il sera redirigé vers une connexion page après tout AJAX à l'appel.
  • Si l'utilisateur est authentifié, mais n'ont pas suffisamment d'autorisations, puis il va voir conviviale erorr message.
  • Si l'utilisateur est authentifié et avoir les autorisations nécessaires, il n'y a pas d'erreurs et HTTP-request sera procédé comme d'habitude.

1voto

chemitaxis Points 352

Si vous voulez attraper le Content-Type = application/json, vous pouvez utiliser ce code :

cordialement !

0voto

user3879365 Points 1

Après beaucoup de tapage essayant d’éviter les redirections vers la page de connexion, j’ai réalisé qu’il s’agit en fait tout à fait approprié pour l’attribut autoriser. Il dit aller et obtenir l’autorisation. À la place pour les appels d’Api qui ne sont pas autorisés, je voulais juste ne pas de révéler que toute information à serait les pirates. Cet objectif a été plus facile à réaliser directement en ajoutant un nouvel attribut dérivé hors Authorize qui cache plutôt le contenu comme une erreur 404 :

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X