10

Tengo una aplicación ASP.NET MVC utilizando Atributos de autorización en Controladores y Acciones. Esto ha estado funcionando bien pero ha aparecido una nueva arruga.ASP.NET MVC: Autorización dentro de una Acción - Patrones sugeridos o ¿esto es un olor?

objeto: Envío

Roles: envío, Contabilidad, usuario general

El envío se mueve a través de un flujo de trabajo. En el estado A, solo puede editarse mediante envío. En el estado B, solo se puede editar mediante Contabilidad.

Tengo un ShipmentController y una acción de edición. Puedo poner un atributo de Autorización para limitar la acción de Edición a solo esos dos roles, pero esto no distingue en qué estado está el Envío. Necesitaría hacer una Autorización dentro de la acción antes de la llamada de servicio para determinar si el usuario está realmente autorizado para ejecutar la acción de edición.

Así que estoy izquierda con dos preguntas:

1) ¿Cuál es una buena manera de tener la autorización dentro de una acción. La acción del controlador llama a un servicio, y el servicio realiza llamadas apropiadas al objeto de envío (cantidad de actualización, fecha de actualización, etc.). Sé con certeza que quiero que el objeto de envío sea independiente de los requisitos de autorización. Por otro lado, no entiendo muy bien si quisiera que el objeto de servicio tuviera conocimiento de la autorización o no. ¿Hay algún buen patrón para esto?

2) ¿Mi problema es realmente un síntoma de mal diseño? En lugar de ShipmentController, ¿debería tener un StateAShipmentController y StateBShipmentController? No tengo ningún polimorfismo incorporado en el objeto de envío (el estado es solo una enumeración), pero tal vez debería y tal vez los controladores deberían reflejar eso.

Supongo que estoy buscando soluciones más generales, no específicas para mi caso. Solo quería dar un ejemplo para ilustrar la pregunta.

Gracias!

+0

¿Por qué no crear su propio filtro de acción tipo [Autorizar] para las cosas relacionadas con el envío? –

+0

crear tu propio filtro [Autorizar] sería una muy mala idea, y es uno que el equipo de desarrollo ASP.NET MVC realmente ha desaconsejado realmente –

+0

@Josh; Estoy en desacuerdo. No es una "idea realmente mala", es solo una que se debe abordar con la debida atención. No he visto ningún artículo público sobre desalentarlo en absoluto, y mucho menos con varios 'realmente' y 'muy'. La única 'sorpresa' de mi conocimiento es que desea heredar del atributo Autorizar proporcionado por el marco, porque de esa manera puede asegurarse de que se dispare de manera confiable en el lugar correcto. – Paul

Respuesta

2

Su atributo de autorización podría obtener el envío de parámetros de acción o datos de ruta y luego tomar una decisión.

Para el número 1, hay una serie de patrones que permiten un comportamiento rico en objetos de dominio. En el envío doble, pasa una referencia a una abstracción de servicio (interfaz) a un método en el objeto. Entonces puede hacer lo suyo. También puede escribir un servicio de aplicación que acepte el envío y haga el trabajo.

En el número 2, no necesariamente. Es posible que deba abstraer el concepto de un "envío contextual" a un servicio que averigüe en qué contexto de envío se encuentra. Pero lo haría YAGNI hasta que lo necesite nuevamente.

1

Puede consultar Rhino.Security, podría utilizarse para implementar la autorización del usuario en este tipo de situaciones.

3

No veo ningún problema con un método de Acción que haga verificaciones de autorización adicionales dentro de él. Puede aprovechar el proveedor Roles para obtener la autorización precisa que está buscando. Disculpe mi sintaxis aquí; es probable que sea difícil y no lo he probado.

[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

Si bien es una solución "simple", huele un poco. La codificación rígida de la autorización en el controlador viola el SRP y, como mínimo, debe refactorizarse en su propia clase. –

+0

Este ejemplo casi pide una implementación de patrón de estado. – Paul

+1

¡je, sí, seguro! Simplista como era, quería asegurarme de que me dirigía a la pregunta del OP, en lugar de empantanarme en los detalles. –

1

Además de la respuesta anterior, se puede devolver un HttpUnauthorizedResult en lugar de la creación de su propio punto de vista de NotAuthorized.Esto redireccionará a la página de inicio de sesión y se comportará igual que el atributo [Autorizar]

Cuestiones relacionadas