Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Фильтры авторизации срабатывают после фильтров аутентификации и до запуска остальных фильтров и вызова методов действий. Цель фильтров авторизации - разграничить доступ пользователей, чтобы к определенным ресурсам приложения имели доступ только определенные пользователи.
Фильтры авторизации реализуют интерфейс 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 позволяет разрешить доступ к ресурсам для анонимных, не авторизованных пользователей. Например, если к контроллеру применяется атрибут 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).