ASP.Net MVC: ¿Se puede anular el atributo AuthorizeAttribute?

Mi proyecto actual es una aplicación web interna creada con ASP.Net MVC a la que agrego autenticación. Tengo un módulo HTTP pre-construido que crea un IPrincipal con los roles apropiados. Si el usuario no está autenticado, obtengo un objeto de usuario con el rol “Público”

Como se trata de una aplicación interna, la mayoría de las páginas son privadas y solo se pueden ver con el rol “Administrador”. Como tengo un controlador base puedo hacer esto:

[Authorize(Roles="Admin")] public abstract class MyControllerBase : Controller { ... } 

Aunque tengo un problema, ya que algunas de las acciones se pueden ver en un sitio web público y si las atribuyo de esta manera:

 [Authorize(Roles="Public")] public class LoginController : MyController { public ActionResult Index() { } } 

La página no se carga porque el usuario no está autenticado. Parece que el Rol de “Público se ignora en la clase heredada. ¿Alguien sabe si los roles pueden ser anulados por las clases heredadas?

También estoy tratando de evitar atribuir todos los controladores con Roles = “Admin”

Gracias, Keith.

Puede derivar un nuevo atributo de AuthorizeAttribute y anular el método OnAuthorization, luego aplicar su atributo personalizado en lugar de Autorizar. A continuación se muestra el método de OnAuthorization de uno de mis atributos personalizados que redirige a una página de error si los privilegios no son suficientes en lugar de redirigir a la página de inicio de sesión.

Sin embargo, no estoy seguro de qué es lo que esto te comprará. Cuando decore su clase con el atributo, presumiblemente tendrá que permitir tanto al Administrador como al Público (¿a quién está restringiendo ya que Público hay alguien que no está autenticado?). Luego tendría que decorar cada uno de los métodos de controlador que deben restringirse a Admin individualmente, ya que el atributo de clase permitiría el acceso de otra manera. Puede lograr este comportamiento con el atributo Autorizar regular simplemente decorando aquellos métodos no disponibles públicamente (o clases que no tienen métodos disponibles públicamente).

Supongo que podría tener su control de atributos para ver si el método al que se llama también está decorado con el atributo y simplemente aprobar la autorización, lo que efectivamente diferiría la autorización al nivel del método. Probablemente tendría que echar un vistazo a RouteData en el AuthorizationContext para obtener la acción y usar la reflexión para tratar de encontrar el método apropiado en función de los parámetros y el tipo de solicitud.

  public override void OnAuthorization( AuthorizationContext filterContext ) { if (filterContext == null) { throw new ArgumentNullException( "filterContext" ); } if (AuthorizeCore( filterContext.HttpContext )) { SetCachePolicy( filterContext ); } else if (!filterContext.HttpContext.User.Identity.IsAuthenticated) { // auth failed, redirect to login page filterContext.Result = new HttpUnauthorizedResult(); } else { ViewDataDictionary viewData = new ViewDataDictionary(); viewData.Add( "Message", "You do not have sufficient privileges for this operation." ); filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData }; } } protected void SetCachePolicy( AuthorizationContext filterContext ) { // ** IMPORTANT ** // Since we're performing authorization at the action level, the authorization code runs // after the output caching module. In the worst case this could allow an authorized user // to cause the page to be cached, then an unauthorized user would later be served the // cached page. We work around this by telling proxies not to cache the sensitive page, // then we hook our custom authorization code into the caching mechanism so that we have // the final say on whether a page should be served from the cache. HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; cachePolicy.SetProxyMaxAge( new TimeSpan( 0 ) ); cachePolicy.AddValidationCallback( CacheValidateHandler, null /* data */); } 

Bueno, al final creo que mi respuesta estaba en la pregunta. En lugar de poner el atributo Autorizar en mi controlador base, he derivado un nuevo AdminBaseController.

 [HandleError] public abstract class MyControllerBase : Controller { ... } [Authorize(Roles="Admin")] public abstract class AdminControllerBase : MyControllerBase { .... } 

Ahora, cualquier controlador que requiera autenticación puede derivarse de AdminControllerBase mientras que mis controladores públicos pueden derivar de MyControllerBase. OO al rescate.