You can derive a new attribute from AuthorizeAttribute and override the OnAuthorization method, then apply your customized attribute instead of Authorize. Below is the OnAuthorization method from one of my customized attributes that redirects to an error page if the privileges aren't sufficient instead of redirecting to the logon page.
I'm not sure exactly what this will buy you, though. When you decorate your class with the attribute, presumably you'll have to allow both Admin and Public (so who are you restricting since Public is anyone who is not authenticated?). You'd then have to decorate each of the controller methods that need to be restricted to Admin individually since the class attribute would allow access otherwise. You can achieve this behavior with the regular Authorize attribute by simply decorating just those non-publicly available methods (or classes that have no publicly available methods).
I suppose you could have your attribute check to see if the method being called is also decorated with the attribute and simply approve the authorization, which would effectively defer the authorization to the method level. You'd probably have to peek into the RouteData on the AuthorizationContext to get the action and use reflection to try and find the appropriate method based on parameters and request type.
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 */);
}