8

Básicamente quiero mostrar un mensaje amistoso cuando alguien no forma parte de un rol que figura en mi atributo. Actualmente, mi aplicación simplemente escupe al usuario de vuelta a la pantalla de inicio de sesión. He leído algunas publicaciones que hablan sobre la creación de un atributo personalizado que simplemente extiende [AuthorizeAttribute], pero estoy pensando que debe haber algo listo para hacer esto.atributo para .net MVC controlador método de acción

¿Puede alguien señalarme en la dirección correcta de donde debo mirar para que no envíe al usuario al formulario de inicio de sesión, sino que simplemente me dispare un mensaje de "no autorizado"?

Respuesta

2

Si simplicidad o el control total de la lógica es lo que quiere puede llamar a esto en su método de acción:

User.IsInRole("NameOfRole"); 

devuelve un bool y se puede hacer el resto de su lógica en función de ese resultado.

Otro que he utilizado en algunos casos es:

System.Web.Security.Roles.GetRolesForUser(); 

Creo que devuelve una cadena [] pero no me cito en eso.

EDIT: Un ejemplo siempre ayuda ...

public ActionResult AddUser() 
{ 
    if(User.IsInRoles("SuperUser") 
    { 
     return View("AddUser"); 
    } 
    else 
    { 
     return View("SorryWrongRole"); 
    } 
} 

Mientras su tipo de retorno es "ActionResult" que podría devolver cualquiera de los tipos de retorno aceptados (ViewResult, PartialViewResult, RedirectResult, JsonResult ...)

+0

así que usando esa lógica, tendría que devolver vistas parciales con "mensajes amistosos" correctos? ¿No es posible abarcar todo el método de acción con un atributo que hace lo mismo? – Kyle

+0

Agregué un ejemplo arriba. Su otra opción es, por supuesto, escribir su propio atributo como usted mencionó (que sería la prueba más limpia, aunque más dura para la unidad), pero definitivamente no es un enfoque listo para usar. –

0

El comportamiento fuera de la caja es que el atributo [Autorizar] devuelve un HTTP 401. El FormsAuthenticationModule (que se carga de forma predeterminada) intercepta este 401 y redirige al usuario a la página de inicio de sesión. Eche un vistazo a System.Web.Security.FormsAuthenticationModule :: OnLeave en Reflector para ver a qué me refiero.

Si desea que el AuthorizeAttribute hacer algo otra que HTTP retorno 401, que tendrá que reemplazar el método AuthorizeAttribute :: HandleUnauthorizedRequest y realizar cierta lógica de negocio en ese país. Como alternativa, sólo cambiar esta parte de ~ \ Web.config:

<forms loginUrl="~/Account/LogOn" timeout="2880" /> 

Y hacer que apunte a una URL diferente, como ~/AccessDenied.

3

Me encontré con este problema hace unos días y la solución es un poco detallada, pero aquí están las partes importantes. En AuthorizeAttribute, el método OnAuthorization devuelve HttpUnauthorizedResult cuando falla la autorización, lo que hace que devolver un resultado personalizado sea un poco difícil.

Lo que terminé haciendo fue crear una clase CustomAuthorizeAttribute y anular el método OnAuthorization para lanzar una excepción. Luego puedo detectar esa excepción con un controlador de errores personalizado y mostrar una página de error personalizada en lugar de devolver un 401 (no autorizado).

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) { 
     if (filterContext == null) { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (AuthorizeCore(filterContext.HttpContext)) { 
      HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; 
      cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
      cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
     } 
     else { 
      // auth failed, redirect to login page 
      // filterContext.Result = new HttpUnauthorizedResult(); 

      throw new HttpException ((int)HttpStatusCode.Unauthorized, "Unauthorized");     
     } 
    } 
} 

entonces en su web.config puede establecer manejadores personalizados para errores específicos:

<customErrors mode="On" defaultRedirect="~/Error"> 
     <error statusCode="401" redirect="~/Error/Unauthorized" /> 
     <error statusCode="404" redirect="~/Error/NotFound" /> 
    </customErrors> 

y luego poner en práctica su propia ErrorController para servir páginas personalizadas.

En IIS7 debe buscar en la configuración Response.TrySkipIisCustomErrors = true; para habilitar sus errores personalizados.

6

que podría ser un poco tarde en la adición de mi $ 0,02, pero al crear su CustomAuthorizationAttribue, puede utilizar la AuthorizationContext.Result property dictar donde el método AuthorizeAttribute.HandleUnauthorizedRequest dirige al usuario.

Aquí es un ejemplo muy simple que le permite especificar la URL en la que un usuario debe ser enviado después de un Error de autorización:

public class Authorize2Attribute : AuthorizeAttribute 
{ 
    // Properties 

    public String RedirectResultUrl { get; set; } 

    // Constructors 

    public Authorize2Attribute() 
     : base() 
    { 
    } 

    // Overrides 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (String.IsNullOrEmpty(RedirectResultUrl)) 
      base.HandleUnauthorizedRequest(filterContext); 

     else 
      filterContext.Result = new RedirectResult(RedirectResultUrl); 
    } 
} 

Y si quisiera volver a dirigir al usuario/error/no autorizada como se sugiere en un post anterior:

[Authorize2(Roles = "AuthorizedUsers", RedirectResultUrl = "/Error/Unauthorized")] 
public ActionResult RestrictedAction() 
{ 
    // TODO: ... 
} 
+0

He hecho algo similar, pero verifico si el usuario está autenticado. Esto me permite rechazar a los usuarios por no estar en un rol, pero no se les pide que inicien sesión –

2

muy similar a crazyarabian, pero sólo a dirigir a mi cadena si el usuario está realmente autentificado. Esto permite que el atributo redireccione a la página de inicio de sesión estándar si no están actualmente conectados, pero a otra página si no tienen permisos para acceder a la url.

public class EnhancedAuthorizeAttribute : AuthorizeAttribute 
{ 
    public string UnauthorizedUrl { get; set; } 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     var redirectUrl = UnauthorizedUrl; 
     if (filterContext.HttpContext.User.Identity.IsAuthenticated && !string.IsNullOrWhiteSpace(redirectUrl)) 
     { 
      filterContext.Result = new RedirectResult(redirectUrl); 
     } 
     else 
     { 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
    } 
} 
Cuestiones relacionadas