10

J'ai une application ASP.NET MVC en utilisant les attributs d'autorisation sur les contrôleurs et les actions. Cela a bien fonctionné mais une nouvelle ride est apparue.ASP.NET MVC: Autorisation dans une Action - Motifs suggérés ou est-ce une odeur?

Objet: Expédition

Rôles: Expédition, Comptabilité, utilisateur général

L'expédition se déplace à travers un flux de travail. Dans l'état A, il peut être édité par Shipping uniquement. Dans l'état B, il peut être édité par Accounting uniquement.

J'ai un ShipmentController, et une action d'édition. Je peux mettre un attribut Authorization pour limiter l'action Edit à ces deux rôles, mais cela ne fait pas la différence entre l'état dans lequel se trouve l'envoi. J'aurais besoin de faire une autorisation dans l'action avant l'appel de service pour déterminer si l'utilisateur est vraiment autorisé à exécuter l'action d'édition.

Je me reste deux questions:

1) Ce qui est une bonne façon d'avoir l'autorisation à l'intérieur d'une action. L'action Contrôleur appelle un service et le service effectue alors les appels appropriés à l'objet Envoi (quantité de mise à jour, date de mise à jour, etc.). Je suis sûr que je veux que l'objet d'expédition soit agnostique de toutes les exigences d'autorisation. D'un autre côté, je ne sais pas vraiment si je voudrais que l'objet de service connaisse l'autorisation ou non. Y a-t-il de bons modèles pour cela?

2) Mon problème est-il réellement un symptôme de mauvaise conception? Au lieu de ShipmentController devrais-je avoir un StateAShipmentController et StateBShipmentController? Je n'ai aucun polymorphisme intégré dans l'objet Shipment (l'état est juste une énumération), mais peut-être que je devrais et peut-être que les contrôleurs devraient refléter cela.

Je suppose que je suis après des solutions plus générales, pas une spécifique pour mon cas. Je voulais juste donner un exemple pour illustrer la question.

Merci!

+0

Pourquoi ne pas créer votre propre filtre d'action [Authorize] pour les éléments liés à l'envoi? –

+0

créer votre propre filtre [Authorize] serait vraiment une très mauvaise idée, et c'est une idée que l'équipe de développeurs ASP.NET MVC a vraiment vraiment déconseillée. –

+0

@Josh; Je ne suis pas d'accord. Ce n'est pas une "vraiment, vraiment mauvaise idée", c'est juste une approche qui doit être abordée avec soin. Je n'ai vu aucun article public sur le décourager du tout, encore moins avec plusieurs «vraiment» et «fortement». Le seul vrai "gotcha" de ma connaissance est que vous voulez hériter de l'attribut Authorize fourni par le framework, parce que de cette façon vous pouvez vous assurer qu'il est déclenché de manière fiable au bon endroit. – Paul

Répondre

2

Votre attribut d'autorisation pourrait obtenir l'expédition à partir des paramètres d'action ou des données de route, puis prendre une décision.

Pour le numéro 1, il existe un certain nombre de modèles qui permettent un comportement riche dans les objets de domaine. En double-dispatch, vous passez une référence à une abstraction de service (interface) à une méthode sur l'objet. Ensuite, il peut faire son truc. Vous pouvez également écrire un service d'application qui prend l'envoi et fait le travail.

Sur le numéro 2, pas nécessairement. Vous devrez peut-être faire abstraction du concept d'un «Envoi contextuel» dans un service qui détermine le contexte d'expédition dans lequel vous vous trouvez. Mais je le ferais jusqu'à ce que vous en ayez besoin.

1

Vous pouvez jeter un oeil à Rhino.Security, il pourrait être utilisé pour mettre en œuvre l'autorisation de l'utilisateur dans ce genre de scénarios.

3

Je ne vois pas de problème avec une méthode Action effectuant d'autres vérifications d'autorisation. Vous pouvez tirer parti du fournisseur de rôles pour l'autorisation détaillée que vous recherchez. S'il vous plaît excusez ma syntaxe ici - il est probablement rugueux et je n'ai pas testé cela.

[Authorize(Roles="Shipping, Accounting")] 
public ActionResult Edit(int id) 
{ 
    Shipment shipment = repos.GetShipment(id); 


    switch (shipment.State) 
    { 
     case ShipmentState.A: 
     if (Roles.IsUserInRole("Shipping")) 
       return View(shipment); 
     else 
       return View("NotAuthorized"); 
     break; 
     case ShipmentState.B: 
     if (Roles.IsUserInRole("Accounting")) 
       return View(shipment); 
     else 
       return View("NotAuthorized"); 
     break; 
     default: 
       return View("NotAuthorized"); 
    } 
} 
+0

Bien que ce soit une solution "simple", ça sent un peu. Le codage en dur de l'autorisation sur le contrôleur viole le SRP, et devrait au minimum être refactorisé dans sa propre classe. –

+0

Cet exemple a presque besoin d'une implémentation de modèle d'état. – Paul

+1

heh ouais c'est sûr! Simpliste que ce soit, je voulais m'assurer de répondre à la question du PO, plutôt que de m'embourber dans les détails. –

1

En plus de la réponse ci-dessus, vous pouvez retourner un HttpUnauthorizedResult au lieu de créer votre propre point de vue pour NotAuthorized.Cela redirigera vers la page de connexion et se comportera comme l'attribut habituel [Authorize]

Questions connexes