Фильтрация Action в MVC, двухуровневый подход — есть ли стандартное решение?

Предположим, у нас есть контроллер

    [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);

        }
    }
  • Вопрос задан
  • 2477 просмотров
Пригласить эксперта
Ответы на вопрос 1
bob_smith
@bob_smith
Стандартного решения нет. Ваше решение вполне логично.

Я просто решил найти самый старый вопрос без ответа и ответить на него :-)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы