Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Фильтры авторизации ограничивают доступ к методам контроллера для определенных пользователей. Однако не стоит их путать с ранее описанными фильтрами аутентификации. Цель фильтров аутентификации - определить, что это за пользователь. А цель фильтров авторизации - определение прав аутентифицированного пользователя в системе.
Все фильтры авторизации реализуют интерфейс IAuthorizationFilter, который расположен в пространстве имен
System.Web.Http.Filters
:
public interface IAuthorizationFilter : IFilter { Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation); }
Логика авторизации может быть реализована самыми разными способами. Но наиболее распространенный подход заключается в
получении данных из объекта HttpRequestContext.Principal
. И если данные запроса не удовлетворяют некоторым условиям, то
клиенту возвращается статусный код 401 (Unauthorized).
Итак, создадим свой фильтр авторизации:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Security.Principal; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace WebApiApp.Filters { public class CustomAuthorizationAttribute : Attribute, IAuthorizationFilter { private string[] usersList; public CustomAuthorizationAttribute(params string[] users) { this.usersList = users; } public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { IPrincipal principal = actionContext.RequestContext.Principal; if (principal == null || !usersList.Contains(principal.Identity.Name) ) { return Task.FromResult<HttpResponseMessage>( actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized)); } else { return continuation(); } } public bool AllowMultiple { get { return false; } } } }
Данный фильтр очень примитивен: он будет смотреть, входит ли логин пользователя в определенный набор логинов, которым разрешен доступ к ресурсу.
В методе ExecuteAuthorizationFilterAsync()
мы получаем из контекста объект IPrincipal, который содержит данные о ранее аутентифицированном
пользователе.
Если IPrincipal не определен или логин пользователя не входит в число разрешенных, то посылается статусный код Unauthorized. Если же все условия соблюдены,
то выполняем метод, к которому применяется атрибут. Для этого вызывается делегат continuation
, который собственно и предоставляет
выполняемый метод.
Применение фильтра:
[CustomAuthorization("eugene")] public string Get(int id) { return "Login: " + User.Identity.Name; }
Надо учитывать, что аутентификация пользователя и создание объекта IPrincipal происходит в фильтре аутентификации, и к моменту авторизации IPrincipal в случае удачной аутентификации должен нести данные о логине пользователя. А в фильтре авторизации указываем набор логинов, которым разрешен доступ.
В большинстве случаев нет необходимости создавать свои механизмы авторизации, так как Web API имеет встроенную реализацию данного фильтра в виде атрибута Authorize. Он имеет два свойства Users и Roles, которые позволяют указать соответственно набор логинов и ролей, для которых разрешен доступ:
[Authorize(Roles = "admins,users", Users="sergey,eugene")] public string Get(int id) { return "Login: " + User.Identity.Name; }
Если мы хотим применить несколько ролей или логинов, то они разделяются запятой. В данном случае доступ к методу Get имеют все пользователи, входящие в группы admins и users, и те, которые имеют логины sergey и eugene.