Autorisation personnalisée dans Asp.net WebApi - quel gâchis?

113

Je lis plusieurs ressources (livres et réponses SO) sur l'autorisation dans WebApi.

Supposons que je souhaite ajouter un attribut personnalisé qui autorise l'accès uniquement à certains utilisateurs:

Cas 1

J'ai vu cette approche de remplacement OnAuthorization , qui définit la réponse si quelque chose ne va pas

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 public override void OnAuthorization(HttpActionContext actionContext)
  {
   if ( /*check if user OK or not*/)
   {
     actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
   }
  }
}

Cas n ° 2

Mais j'ai également vu cet exemple similaire qui remplace également OnAuthorizationmais avec l'appel à base:

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
  base.OnAuthorization(actionContext);

    // If not authorized at all, don't bother

    if (actionContext.Response == null)  
     {
      //...
     }
}

Ensuite, vous vérifiez si le HttpActionContext.Responseest défini ou non. S'il n'est pas défini, cela signifie que la demande est autorisée et que l'utilisateur est ok

Cas n ° 3

Mais j'ai également vu cette approche consistant à remplacer IsAuthorized :

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 protected override bool IsAuthorized(HttpActionContext context)
  {
   if ( /*check if user OK or not*/)
   {
    return true;// or false
   }
  }
}

Cas n ° 4

Et puis j'ai vu un exemple similaire mais avec appel de base.IsAuthorized (context):

protected override bool IsAuthorized(HttpActionContext context)
{
 if (something1 && something2 && base.IsAuthorized(context)) //??
 return true;
 return false;
}

Encore une chose

Et finalement Dominick a dit ici :

Vous ne devez pas remplacer OnAuthorization - car il vous manquerait la gestion [AllowAnonymous].

Des questions

  • 1) Quelles méthodes dois-je utiliser: IsAuthorizedou OnAuthorization? (ou quand utiliser lequel)

  • 2) Quand dois-je appeler base.IsAuthorized orbase.OnAuthorization`?

  • 3) Est-ce ainsi qu'ils l'ont construit? que si la réponse est nulle alors tout va bien? (cas n ° 2)

NB

Veuillez noter que j'utilise (et que je souhaite utiliser) uniquement AuthorizeAttributece qui hérite déjà de AuthorizationFilterAttribute

Pourquoi ?

Parce que je suis à la première étape de: http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

entrez la description de l'image ici

Quoi qu'il en soit, je demande via l'extension de l'attribut Authorize.

Royi Namir
la source
De quoi avez-vous besoin pour remplacer l'attribut Authorize? Quel est le cas d'utilisation que vous souhaitez atteindre? Si vous devez autoriser l'accès à certains utilisateurs, pourquoi ne pas utiliser l'attribut [Authorize (Users = "Admin")] comme celui-ci?
Taiseer Joudeh
1
@TaiseerJoudeh Par exemple Essayez d'autoriser les utilisateurs entre 10h00 et 12h00 (configurable). vous ne pouvez pas faire cela avec des rôles simples et attr autorisé. vous devez faire votre propre logique
Royi Namir

Réponses:

93

Quelles méthodes dois-je utiliser: IsAuthorized ou OnAuthorization? (ou quand utiliser lequel)

Vous étendrez AuthorizationFilterAttributesi votre logique d'autorisation ne dépend pas de l'identité établie et des rôles. Pour l'autorisation liée à l'utilisateur, vous étendrez et utiliserez AuthorizeAttribute. Pour le premier cas, vous remplacerez OnAuthorization. Dans ce dernier cas, vous remplacerez IsAuthorized. Comme vous pouvez le voir à partir du code source de ces attributs, OnAuthorizationest marqué virtuel pour que vous puissiez le remplacer si vous dérivez AuthorizationFilterAttribute. D'autre part, la IsAuthorizedméthode est marquée virtuelle dans AuthorizeAttribute. Je pense que c'est un bon indicateur de l'utilisation prévue.

quand dois-je appeler base.IsAuthorized ou base.OnAuthorization?

La réponse à cette question réside dans le fonctionnement général de l'OO. Si vous remplacez une méthode, vous pouvez soit fournir complètement une nouvelle implémentation, soit utiliser l'implémentation fournie par le parent et améliorer le comportement. Par exemple, prenons le cas de IsAuthorized(HttpActionContext). Le comportement de la classe de base est de vérifier l'utilisateur / le rôle par rapport à ce qui est spécifié dans le filtre par rapport à l'identité établie. Dites, vous voulez faire tout cela mais en plus, vous voulez vérifier autre chose, peut être basé sur un en-tête de demande ou quelque chose. Dans ce cas, vous pouvez fournir un remplacement comme celui-ci.

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    bool isAuthroized = base.IsAuthorized(actionContext);
    // Here you look at the header and do your additional stuff based on actionContext
    // and store the result in isRequestHeaderOk
    // Then, you can combine the results
    // return isAuthorized && isRequestHeaderOk;
}

Je suis désolé mais je ne comprends pas votre Q3. BTW, le filtre d'autorisation existe depuis longtemps et les gens l'utilisent pour toutes sortes de choses et parfois de manière incorrecte.

Encore une chose. Et enfin, il y avait ce type ici qui a dit: Vous ne devriez pas remplacer OnAuthorization - parce que vous manqueriez de traitement [AllowAnonymous].

Le gars qui a dit que c'est le Dieu du contrôle d'accès - Dominick. De toute évidence, ce sera correct. Si vous regardez l'implémentation de OnAuthorization(copié ci-dessous),

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

    if (!IsAuthorized(actionContext))
    {
        HandleUnauthorizedRequest(actionContext);
    }
}

l'appel à SkipAuthorizationest la partie qui garantit que les AllowAnonymousfiltres sont appliqués, c'est-à-dire que l'autorisation est ignorée. Si vous remplacez cette méthode, vous perdez ce comportement. En fait, si vous décidez de baser votre autorisation sur les utilisateurs / rôles, vous auriez alors décidé de dériver AuthorizeAttribute. La seule option correcte qui vous reste à ce moment-là sera de remplacer IsAuthorizedet non celle déjà remplacée OnAuthorization, bien qu'il soit techniquement possible de le faire.

PS. Dans l'API Web ASP.NET, il existe un autre filtre appelé filtre d'authentification. L'idée est que vous l'utilisiez pour l'authentification et le filtre d'autorisation pour l'autorisation, comme son nom l'indique. Cependant, il existe de nombreux exemples où cette frontière est truquée. De nombreux exemples de filtres d'authentification feront une sorte d'authentification. Quoi qu'il en soit, si vous avez le temps et que vous souhaitez en savoir un peu plus, jetez un œil à cet article MSDN . Avertissement: Il a été écrit par moi.

Badri
la source
Merci encore, mais si je lis entre les lignes, IsAuthenticated est appelé par OnAuthirization, alors pourquoi ne pas remplacer OnAuthorization et appeler base.OnAuthorization puis vérifier la réponse?
Royi Namir
Vous pouvez certainement, si c'est ce que vous voulez.
Badri
Dans ma troisième question, je voulais dire: après avoir exécuté la fonction de base - base.OnAuthorization par exemple, le seul moyen de vérifier si cela a réussi - est d'inspecter la propriété Response ?, ps les exemples sont tirés de votre livre :-)
Royi Namir
Oui, vous recherchez généralement le code d'état 401 mais pas nul, pour autant que je sache. BTW, je ne me souviens pas avoir écrit sur la priorité OnAuthorizationdans mon livre. Je suis sûr que je n'aurais pas écrit sur la vérification de la réponse pour null, car c'est la première fois que j'en entends parler :)
Badri
Oui, je me suis confondu avec l'autre livre. Je lis 3 livres simultanément: securty (le vôtre), pratique (le vôtre) et webapi pro (Tugberk's, Zeitler, Ali). Comme vous pouvez le voir - ils l'ont fait là-bas: i.stack.imgur.com/LNGi4.jpg - ils ont juste vérifié si nul, alors devrais-je vérifier les codes nuls ou d'erreur?
Royi Namir
18

Ok, ma suggestion est de faire ce qui suit en supposant que vous utilisez des jetons de support OAuth pour protéger votre API Web et que vous définissez le allowedTime comme une revendication pour l'utilisateur lorsque vous avez émis le jeton. Vous pouvez en savoir plus sur l' authentification basée sur les jetons ici

  1. Créer CustomAuthorizeAttribute qui dérive de AuthorizationFilterAttribute
  2. override OnAuthorizationAsyncet utilisez l'exemple de code ci-dessous:

     public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
    {
    
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
    
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (!principal.Identity.IsAuthenticated)
            {
                return Task.FromResult<object>(null);
            }
    
            var userName = principal.FindFirst(ClaimTypes.Name).Value;
            var userAllowedTime = principal.FindFirst("userAllowedTime").Value;
    
            if (currentTime != userAllowedTime)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Not allowed to access...bla bla");
                return Task.FromResult<object>(null);
            }
    
            //User is Authorized, complete execution
            return Task.FromResult<object>(null);
    
        }
    }
  3. Désormais, dans vos contrôleurs, vous utilisez l'attribut CustomAuthorize pour protéger vos contrôleurs à l'aide de cette logique d'autorisation.
Taiseer Joudeh
la source
1
Merci. Mais j'utilise actuellement AuthorizeAttributece qui hérite AuthorizationFilterAttributeet -aussi pour apprendre, j'ai spécifiquement demandé quelle méthode devrais-je utiliser et à propos de la réponse a un contenu ou non ...
Royi Namir
3

ASP.NET v5 Introduction d'un tout nouveau système d'autorisation. Pour ceux qui vont utiliser .NET 5, je suggère de passer à Microsoft.AspNet.Authorization.

Quasiment elle enveloppe les dégâts causés en gardant à la fois System.Web.Http.Authorizeet System.Web.Mvc.Authorizeet d' autres implémentations d'authentification plus anciennes.

Il fournit une très bonne abstraction des types d'action (créer, lire, mettre à jour, supprimer), des ressources, des rôles, des revendications, des vues, des exigences personnalisées et permet de créer des gestionnaires personnalisés, combinant l'un des éléments ci-dessus. De plus, ces gestionnaires peuvent également être utilisés en combinaison.

Dans ASP.NET v5, l'autorisation fournit désormais un rôle déclaratif simple et un modèle basé sur une stratégie plus riche où l'autorisation est exprimée en exigences et les gestionnaires évaluent les revendications d'un utilisateur par rapport aux exigences. Les vérifications impératives peuvent être basées sur des politiques simples ou des politiques qui évaluent à la fois l'identité de l'utilisateur et les propriétés de la ressource à laquelle l'utilisateur tente d'accéder.

Anestis Kivranoglou
la source
14
Bon à savoir, mais ne répond pas du tout à la question.
Zero3