Предположим, у нас есть контроллер
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Index2()
{
return View();
}
}
Фильтр отключает доступ ко всему контроллеру, если у пользователя нет роли Admin. Обычный подход.
Меняем контроллер:
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
public ActionResult Index()
{
return View();
}
[Authorize(Roles="Admin2")]
public ActionResult Index2()
{
return View();
}
}
К методу Index2 добавился фильтр по роли Admin2. Если у пользователя есть роль Admin, то он попадет в Index, если есть Admin и Admin2, то попадет в Index и Index2. А если надо пользователя пустить в Index2, но НЕ пускать в Index? То есть чтобы фильтр проверял сначала доступность контроллера пользователю, а потом доступность метода пользователю, если метод доступен, а контроллер нет — пускал в метод.
Я написал свою обертку для ActionFilterAttribute:
//Проверка метода на доступность пользователю. Применяется к методу так:
// [Inc.Modules.Output(AccessType=Inc.Modules.OutputAttribute.eAccessType.Everybody)]
[AttributeUsage(AttributeTargets.Method,AllowMultiple=false)]
public class OutputAttribute : ActionFilterAttribute
{
public enum eAccessType
{
None, //Никому
Everybody, //Всем
Authorized //Авторизованным
}
private eAccessType mAccessType = eAccessType.None;
public virtual eAccessType AccessType
{
get { return mAccessType; }
set { mAccessType = value; }
}
public OutputAttribute()
{
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
OnActionExecutingFilter(filterContext, mAccessType);
}
//Проверяем доступность метода пользователю.
protected bool OnActionExecutingFilter(ActionExecutingContext filterContext, eAccessType accessType)
{
try
{
switch (accessType)
{
case eAccessType.None:
filterContext.Result = new EmptyResult();
return false;
case eAccessType.Authorized:
break;
case eAccessType.Everybody:
break;
}
}
catch (Exception ex)
{
}
base.OnActionExecuting(filterContext);
return false;
}
}
//Проверка класса на доступность пользователю. Применяется к классу так:
// [Inc.Modules.OutputClass(AccessType=Inc.Modules.OutputAttribute.eAccessType.Everybody)]
[AttributeUsage(AttributeTargets.Class)]
public class OutputClassAttribute : OutputAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//По-умолчанию проверяем на основе атрибута класса.
eAccessType accessType = AccessType;
try
{
//Получаем атрибут вызываемого метода. Если есть - проверяем на основе него.
object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(OutputAttribute), false);
if (attributes != null && attributes.Length > 0)
{
OutputAttribute attrib = (OutputAttribute)attributes[0];
accessType = attrib.AccessType;
}
}
catch (Exception ex)
{
}
OnActionExecutingFilter(filterContext, accessType);
}
}