Фильтры авторизации

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

Фильтры авторизации срабатывают после фильтров аутентификации и до запуска остальных фильтров и вызова методов действий. Цель фильтров авторизации - разграничить доступ пользователей, чтобы к определенным ресурсам приложения имели доступ только определенные пользователи.

Фильтры авторизации реализуют интерфейс IAuthorizationFilter:

namespace System.Web.Mvc
{
    public interface IAuthorizationFilter
    {
        void OnAuthorization(AuthorizationContext filterContext);
    }
}

И если при получении запроса окажется, что к запрашиваемому действию контроллера применяется данный фильтр, то сначала срабатывает метод OnAuthorization данного интерфейса. И если фильтр одобрит запрос, то далее вызывается действие. Иначе действие не будет работать.

В ASP.NET MVC 5 имеется встроенная реализация данного фильтра - AuthorizeAttribute. Он применяется посредством установки атрибута [Authorize] над контроллером или методом контроллера. Например:

[Authorize]
public class HomeController : Controller
{
	//.........................
}

Атрибут AllowAnonymous

Атрибут AllowAnonymous позволяет разрешить доступ к ресурсам для анонимных, не авторизованных пользователей. Например, если к контроллеру применяется атрибут Authorize, то фреймворк сначала будет смотреть, есть ли у пользователя необходимые права для доступа к методу контроллера. Однако в этом случае мы попадаем в замкнутый круг - чтобы авторизоваться, надо обратиться к методу Login, но чтобы обратиться к этому методу, уже надо быть авторизованным. Поэтому применяется атрибут AllowAnonymous, который открывает публичный доступ к методу контроллера.

Использование ролей при авторизации

Система авторизации в mvc позволяет настроить доступ к ресурсам сайта для отдельных пользователей или групп пользователей. Для подобной настройки можно использовать два свойства атрибута AuthorizeAtribute:

  • Users - содержит перечисление имен пользователей, которым разрешен вход

  • Roles - содержит перечисление имен ролей, которым разрешен вход

Использование свойств Users и Roles:

[Authorize (Users="eugene, sergey")]
public ActionResult Index()
{
	.............
}
[Authorize (Roles="admin")]
public ActionResult Create()
{
	.............
}
[Authorize (Roles="admin, moderator", Users="eugene, sergey")]
public ActionResult Edit()
{
	.............
}

В случае если роли или пользователи не указаны, то доступ к методам контроллера имеет любой аутентифицированный пользователь.

Создание собственного фильтра авторизации

Выше мы посмотрели, как работает фильтр авторизации. Однако за кадром остались принципы работы данного фильтра. Для этого мы создадим свой фильтр.

Наиболее простой и безопасный способ создания своего фильтра авторизации - это наследование класса от атрибута AuthorizeAtribute и переопределение метода AuthorizeCore:

using System;
using System.Web;
using System.Web.Mvc;
using System.Linq;

namespace FiltersApp.Filters
{
    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        private string[] allowedUsers = new string[] { };
        private string[] allowedRoles = new string[] { };

        public MyAuthorizeAttribute()
        {}
 
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (!String.IsNullOrEmpty(base.Users))
            {
                allowedUsers = base.Users.Split(new char[] { ',' });
                for (int i = 0; i < allowedUsers.Length; i++)
                {
                    allowedUsers[i] = allowedUsers[i].Trim();
                }
             }
             if(!String.IsNullOrEmpty(base.Roles))
             {
                 allowedRoles = base.Roles.Split(new char[] { ',' });
                 for (int i = 0; i < allowedRoles.Length; i++)
                 {
                    allowedRoles[i] = allowedRoles[i].Trim();
                 }
             }  
            
            return httpContext.Request.IsAuthenticated &&
                 User(httpContext) &&  Role(httpContext);
        }

        private bool User(HttpContextBase httpContext)
        {
            if(allowedUsers.Length>0)
            {
                return allowedUsers.Contains(httpContext.User.Identity.Name);
            }
            return true;
        }
 
        private bool Role(HttpContextBase httpContext)
        {
            if (allowedRoles.Length > 0)
            {
                for (int i = 0; i < allowedRoles.Length; i++)
                {
                    if (httpContext.User.IsInRole(allowedRoles[i]))
                        return true;
                }
                return false;
            }
            return true;
        }
    }
}

Массивы пользователей и ролей помогают провести детальную авторизацию. В базовом классе атрибута определены переменные для ролей и пользователей, которых мы передаем в атрибут. И, обратившись к этим переменным через базовый класс - base.Roles и base.Users, мы их можем получить. Так, если у нас используются следующие роли: Roles="admin, moderator", то свойство base.Roles также будет иметь значение "admin, moderator". И, выполняя манипуляции со строкой - разбиение по запятой, отсечение начальных и конечных пробелов, мы можем поместить все переданные роли в массив.

Другим моментом использования атрибута является применение объекта контекста HttpContextBase. С его помощью можно получить контекст запроса и информацию о пользователе, например, аутентифицирован ли пользователь в системе.

Применение фильтра подобно применению стандартной версии:

[MyAuthorize (Roles="admin, moderator", Users="eugene, sergey")]
public ActionResult Index()
{
	.............
}

Переопределение атрибута AuthorizeAtribute наиболее безопасный способ создания механизма авторизации, по сравнению, скажем, с реализацией в своем классе интерфейса IAuthorizationFilter. Поэтому в случаях, когда вам надо создать свой класс атрибута авторизации, рекомендуется именно этот способ.

Но можно и сочетать наследование атрибута и переопределение интерфейса IAuthorizationFilter:

public class CustomAuthAttribute : AuthorizeAttribute
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
		// если пользователь не принадлежит роли admin, то он перенаправляется на Home/About
        bool auth = filterContext.HttpContext.User.IsInRole("admin");
        if(!auth)
        {
            filterContext.Result = new RedirectToRouteResult(
                new System.Web.Routing.RouteValueDictionary { 
				{ "controller", "Home" }, { "action", "About" } 
            });
        }
    }
}

Хотя в предыдущих примерах переопределение авторизации по сути не имело смысла, однако все-таки может потребоваться реализация своего атрибута. Например, чтобы администраторам сервера сайта не приходилось каждый раз набирать пароль при входе на сайт, мы можем сделать следующую реализацию атрибута:

public class LocalAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return httpContext.Request.IsLocal || base.AuthorizeCore(httpContext);
    }
}

Переопределенный атрибут также позволяет использовать роли и пользователей:

[LocalAuthorize (Roles="admin", Users="eugene, sergey")]
public ActionResult Index()
{
	.............
}

Однако в этом случае заходить на сайт смогут не только указанные роли и пользователи, но и локальные пользователи для данной машины (что мы узнаем с помощью свойства httpContext.Request.IsLocal).

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850