2012-06-14 24 views
16

tengo un método llamado controlador Edit en el que el usuario puede editar los datos que habían creado como tal ...ASP.NET MVC atributo sólo para permitir al usuario editar su/su propio contenido

public ActionResult Edit(int id) 
{ 
    Submission submission = unit.SubmissionRepository.GetByID(id); 
    User user = unit.UserRepository.GetByUsername(User.Identity.Name); 

    //Make sure the submission belongs to the user 
    if (submission.UserID != user.UserID) 
    { 
     throw new SecurityException("Unauthorized access!"); 
    } 

    //Carry out method 
} 

Este método funciona bien, sin embargo, es un poco desordenado para poner en cada método de edición del controlador. Cada tabla siempre tiene un UserID por lo que me preguntaba si había una manera más fácil de automatizar esto a través de un atributo [Authorize] o algún otro mecanismo para hacer el código más limpio.

Respuesta

24

Sí, se puede lograr que a través de una costumbre Autorizar atributo:

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var authorized = base.AuthorizeCore(httpContext); 
     if (!authorized) 
     { 
      return false; 
     } 

     var rd = httpContext.Request.RequestContext.RouteData; 

     var id = rd.Values["id"]; 
     var userName = httpContext.User.Identity.Name; 

     Submission submission = unit.SubmissionRepository.GetByID(id); 
     User user = unit.UserRepository.GetByUsername(userName); 

     return submission.UserID == user.UserID; 
    } 
} 

y luego:

[MyAuthorize] 
public ActionResult Edit(int id) 
{ 
    // Carry out method 
} 

y supongamos que se necesita para alimentar a esta instancia presentación que captan en la costumbre atributo como parámetro de acción para evitar golpear la base de datos una vez más, podría hacer lo siguiente:

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var authorized = base.AuthorizeCore(httpContext); 
     if (!authorized) 
     { 
      return false; 
     } 

     var rd = httpContext.Request.RequestContext.RouteData; 

     var id = rd.Values["id"]; 
     var userName = httpContext.User.Identity.Name; 

     Submission submission = unit.SubmissionRepository.GetByID(id); 
     User user = unit.UserRepository.GetByUsername(userName); 

     rd.Values["model"] = submission; 

     return submission.UserID == user.UserID; 
    } 
} 

y luego:

[MyAuthorize] 
public ActionResult Edit(Submission model) 
{ 
    // Carry out method 
} 
+1

Gracias! Voy a hacer esto más genérico. Al igual que have submission implementar una interfaz llamada IUserOwnable que tiene un UserID. Y luego pasar el repositorio al Atributo donde obtiene un IUserOwnable y comparar ese ID de usuario del usuario con el ID de usuario de IUserOwnable –

+0

Claro, esto podría hacerse tan genérico como desee para satisfacer sus requisitos específicos. –

+0

Buen enfoque. Estaba saltando que ahora tendrá un atributo incorporado en ese –

-1

recomiendo leer sobre la AuthorizeAttribute (ver here). Además, ¿has visto this publicación? Explica cómo anular las características internas de autenticación y cómo usar IPrincipal y IIdentity.

1

Sugeriría que extraiga la lógica de la acción/controlador y cree una clase de dominio para manejar esa lógica.

Los métodos de acción solo deberían tratar de obtener datos y enviarlos a la vista. Puede crear algo lo suficientemente genérico para manejar sus necesidades, pero también seguirá el principio de responsabilidad única.

public class AuthorizedToEdit 
{ 
    protected override bool AuthorizeCore(string user, int itemId) 
    { 
     var userName = httpContext.User.Identity.Name; 

     var authUsers = SubmissionRepository.GetAuthoriedUsers(itemId); 

     return authUsers.Contains(user); 
    } 
} 

Esto también permitirá tener la flexibilidad más adelante para permitir que algo así como los usuarios administradores

Cuestiones relacionadas