Программист прикладного уровня
4,1
рейтинг
31 июля 2014 в 19:36

Разработка → Аутентификация и авторизация в ASP.NET Web API перевод tutorial

Вы создали WebAPI и теперь хотите контролировать доступ к нему? В этой серии статей мы рассмотрим несколько вариантов защиты WebAPI от неавторизрованых пользователей. Серия будет охватывать обе стороны, и аутентификацию и авторизацию пользователей.

  • Аутентификация — позволяет однозначно идентифицировать пользователя. Например, Алиса входит в систему со своим логином и паролем, и сервер использует эти данные для аутентификации Алисы.
  • Авторизация решает может ли пользователь выполнить те или иные действия. Например, Алиса может иметь право на чтение ресурса, но не может создать новый ресурс.


Первая серия статей дает общий обзор аутентификации и авторизации в ASP.NET Web API. Другие статьи описывают общие сценарии аутентификации для WebAPI.

Аутентификация


WebAPI предполагает что аутентификацию проводит хост, в котором он размещается. Для веб-хостинга хостом является IIS, который использует HTTP модули для аутентификации. Вы можете сконфигурировать свой проект на использование модулей аутентификации встроенных в IIS или ASP.NET, или же написать собственный модуль HTTP, для выполнения кастомной проверки подлинности.

Когда хост проводит аутентификацию пользователя, он создает объект IPrincipal, который представляет собой контекст безопасности в котором исполняется код. Созданный объект прикрепляет к текущему потоку, и к нему можно обратиться через свойство Thread.CurrentPrincipal. Контекст безопасности содержит связанный с ним объект Identity, с информацией о пользователе. Если пользователь прошел аутентификацию, свойство Identity.IsAuthenticated вернет значение true. Для анонимных запросов свойство вернет false.

Использование HTTP обработчиков сообщений для аутентификации.


Вместо использования хоста, логику аутентификации можно поместить в обработчик HTTP сообщения. В этом случае, обработчик сообщения исследует HTTP запрос и сам задаст контекст безопасности.

Несколько примеров для чего может понадобиться аутентификация в обработчиках сообщений:
  • HTTP модуль видит все запросы проходящие по каналу ASP.NET, обработчик видит только запросы предназначенные WebAPI
  • Вы можете установить отдельные обработчики сообщений на каждый маршрут, применяя различные схемы аутентификации
  • HTTP модули специфичны для IIS. Обработчики сообщений независимы от хоста, и могут быть использованы как в случае web-хостинга, так и при self-хостинге.
  • HTTP модули учавствуют при логгинге IIS, аудите и т.д.
  • HTTP модули запускаются раньше в цепочке прохождения запроса. Если проводите аутентификацию в обработчике сообщений, контекст безопасности не будет установлен пока не будет запущен обработчик. Кроме того, контекст безопасности возвращается к предыдущему состоянию когда ответ на запрос покинет обработчик сообщения.


В общем, если вы не собираетесь использовать self-хостинг, использование HTTP модулей аутентификации лучший вариант. В противном случае логику стоит вынести в обработчики сообщений.

Установка контекста безопасности


Если ваше приложение выполняет какую-либо логику связанную с аутентификацией, вы должны задать контекст безопасности в двух свойствах:
  • Thread.CurrentPrincipal — стандартный путь задать контекст безопасности для потока в .NET
  • HttpContext.Current.User — свойство специфичное для ASP.NET


Следующий код показывает как задать контекст безопасности:
private void SetPrincipal(IPrincipal principal)
{
    Thread.CurrentPrincipal = principal;
    if (HttpContext.Current != null)
    {
        HttpContext.Current.User = principal;
    }
}


Для веб-хостинга, вы должны задать контекст безопасности в обоих свойствах, иначе контекст безопасности может стать несогласованным. Для обеспечения независимости вашего кода от способа хостинга, следует выставлять проверку на null для свойства HttpContext.Current, как показано в коде. В случае self-хостинга, его значение будет null и задавать контекст безопасности не требуется.

Авторизация


В цепочке обработчиков запроса авторизация находится ближе к контроллеру. Это позволяет проводить тонкую настройку доступа к ресурсам.
  • Фильтры авторизации отрабатывают до методов контроллера. Если запрос не авторизован, фильтр вернет сообщение об ошибке, а метод контроллера не будет вызван.
  • В методе контроллера вы можете получить текущий контекст безопасности из свойства ApiController.User. Например, вы можете фильтровать список ресурсов в зависимости от имени пользователя, возвращая только доступные для него.



Использование аттрибута [Authorize]


WebAPI предоставляет встроенный фильтр авторизации, AuthorizeAttribute, этот фильтр проверяет авторизован ли пользователь. Если нет, фильтр вернет код состояния HTTP 401 (Не авторизован), без вызова метода.
Вы можете применять фильтр как глобально, так и на уровне контроллера или на уровне методов.

Фильтр на глобальном уровне: чтобы ограничить доступ для каждого контроллера WebAPI, добавьте фильтр AuthorizeAttribute в глобальный список фильтров:
public static void Register(HttpConfiguration config)
{
    config.Filters.Add(new AuthorizeAttribute());
}


Фильтр на уровне контроллера: для ограничения доступа к конкретному контроллеру, добавьте фильтр в качестве атрибута класса контроллера:
// Require authorization for all actions on the controller.
[Authorize]
public class ValuesController : ApiController
{
    public HttpResponseMessage Get(int id) { ... }
    public HttpResponseMessage Post() { ... }
}


Фильтр на уровне метода: для ограничения доступа к методу, добавьте к нему атрибут:
public class ValuesController : ApiController
{
    public HttpResponseMessage Get() { ... }

    // Require authorization for a specific action.
    [Authorize]
    public HttpResponseMessage Post() { ... }
}


Кроме того, в можете задать ограничение на контроллер, и разрешить анонимный доступ на отдельные методы при помощи атрибута [AllowAnonymous]. В следующем примере, доступ к методу Post ограничен, а метод Get доступен для анонимных вызовов:
[Authorize]
public class ValuesController : ApiController
{
    [AllowAnonymous]
    public HttpResponseMessage Get() { ... }

    public HttpResponseMessage Post() { ... }
}


В предыдущих примерах, фильтр позволял получить доступ любому пользователю прошедшему проверку подлинности, запрещая доступ только анонимным пользователям. Вы также можете предоставить доступ конкретным пользователям или ролям:
// Restrict by user:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
   
// Restrict by role:
[Authorize(Roles="Administrators")]
public class ValuesController : ApiController
{
}


Фильтр AuthorizeAttribute для контроллеров WebAPI находится в пространстве имен System.Web.Http. Существует аналогичный фильтр для контроллеров MVC в пространстве имен System.Web.Mvc. Этот тип несовместим с контроллерами WebAPI.


Кастомные фильтр авторизации


Кастомный фильтр должен быть унаследован от одного из следующих типов:
  • AuthorizeAttribute. Наследуйте этот класс для реализации синхронной логики авторизации на основе текущего пользователя или роли пользователя.
  • AuthorizationFilterAttribute. Данный класс пригодится для реализации логики авторизации необязательно основанной на пользователе или его роли.
  • IAuthorizationFilter. Реализуйте этот интерфейс для асинхронной логики авторизации. Например ваша авторизация предполагает асинхронные или сетевые вызовы (если логика завязана на процессорных вычислениях, то лучше наследоваться от AuthorizationFilterAttribute, чтобы не писать асинхронные методы)


Следующая диаграмма показывает иерархию классов фильтров:


Авторизация внутри метода контроллера


В некоторых случаях можно разрешить выполнение запроса, но изменить поведение на основе контекста безопасности. Например, результат запроса зависит от роли пользователя. Внутри метода контроллера вы можете получить текущий контекст безопасности обратившись к свойству ApiController.User:
public HttpResponseMessage Get()
{
    if (User.IsInRole("Administrators"))
    {
        // ...
    }
}


* Перевод выполнен в вольном стиле, возможно кого-то покоробят англицизмы наподобие 'кастомный', но эти слова стали частью it жаргона, и русский перевод не воспринимается как должно.

P.S. Если вы хотите проводить отладку с авторизацией в студии, на локальном IIS'е (Local IIS Web server), то здесь можно почитать как включить в нем возможность авторизации.
Развивать тему настройки доступа в WebAPI дальше?
95%
(207)
Да
5%
(12)
Нет

Проголосовало 219 человек. Воздержалось 40 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Перевод: Mike Wasson
Ogoun @Ogoun
карма
59,0
рейтинг 4,1
Программист прикладного уровня
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (17)

  • 0
    HTTP модули запускаются раньше в цепочке прохождения запроса. Если проводите аутентификацию в обработчике сообщений, контекст безопасности не будет установлен пока не будет запущен обработчик. Кроме того, контекст безопасности возвращается к предыдущему состоянию когда ответ на запрос покинет обработчик сообщения.

    Это каким же образом контекст безопасности вернется к предыдущему состоянию?
  • +1
    Вообще уже давно пора рассказывать про OWIN и забыть про модули и хэндлеры из Asp.Net. Делать аутентификацию через MessageHandler я бы то же не стал, так как есть OWIN Authentication Middleware, который позволяет сделать централизованный механизм аутентификации для всех вызовов независимо от используемого в дальнейшем фрэймфорка.
    • +1
      OWIN Authentication Middleware, который позволяет сделать централизованный механизм аутентификации для всех вызовов независимо от используемого в дальнейшем фрэймфорка.


      Как централизированный механизм это не работает пока вообще. В ASP.NET стеке вчистую это будет работать только с SignalR или WebApi и то под 4.5 фреймворком, в продуктивных системах я думаю это не больше 5-10% от всех коммерческих ASP.NET приложений в лучшем случае. Но это сугубо мое мнение.

      На текущий момент даже совместимые Owin технологии практически всегда применяются в связке с зависимыми от System.Web технологиями, что автоматически делает более вероятным использование, именно HttpModules и уже в качестве адаптера для Owin компонентов Microsoft.Owin.SystemWeb(Katana). Поэтому аутентификация до сих пор практически всегда будет реализована на базе модулей. Даже для OWIN совместимой части стека.

      • +1
        Интеграция OWIN работает отлично со всеми фреймворками. Да, для MVC требуется пока что интеграция OWIN с System.Web, но работает он отлично и позволяет по максимуму исключить модули. Вообще в проде уже достаточно софта на 4.5. Ради интереса попробуйте сделать аутентификацию через OAuth2 и WS-Federation через модули на одном хосте.

        Самое главное — вы через полгода-год будете опять все переписывать? Зачем сейчас на это закладываться? Ведь если народ выбирает способ аутентификации — то проект в самом начале(скорее всего), а это значит есть возможность использовать 4.5+(нет смысла не делать этого — 2003 серваков я на проде уже года 3 не видел).

        Вот прямо сейчас смотрю на проект в котором используются OWIN Authentication Middleware для аутентификации в MVC, WebApi и SignalR. Все HttpModule's были выпилены из проекта. В middleware еще и централизованое логирование, поддержка IoC, детерменированность порядка выполнения как минимум.

        А в целом рекомендую начать знакомство с thinktecture@github
        • 0
          Интеграция OWIN работает отлично со всеми фреймворками. Да, для MVC требуется пока что интеграция OWIN с System.Web, но работает он отлично и позволяет по максимуму исключить модули.


          Работает оно правильно только если вы используете Katana компоненты для всего и явно или неявно(если поставщик модуля учитывает наличие IIS) превращаете ваше middleware в http модули. Если вы это не делаете, или используете компоненты, которые этого не учитывают, оно работает неправильно, причем еще и без явных ошибок, для разработчика, который не понимает, как надо верное owin midleware использовать в связке с IIS Integrated pipe.

          Ради интереса попробуйте сделать аутентификацию через OAuth2 и WS-Federation через модули на одном хосте.

          И какие сложности возникли у вас при этом, которых удалось избежать при использовании OWIN для MVC.
          • 0
            1. WebHost и вперед. WebApi не зареганый как модуль отлично работает. В любом случае — это предпочительный вариант в свете Asp.Net vNext.
            2. Отдайте 401 статус код и посмотрите какой из модулей его обработает и как.

            Повторюсь, на данный момент в свете Asp.Net vNext инвестировать время в разработку HttpModules не эффективно. Если вложить ресурсы в развитие базы кода с использованием OWIN — То это будет гораздо эффективнее(и возможно даже кроссплатформенней) и не придется выкидывать код или кардинально его переделывать.

            • 0
              Я не совсем понял к чему эти пункты.
              1. Да, работает, и так и так внутри абсолютно одинаково.
              2. Могу предположить, что не один из интересующих нас, потому что когда хендлер обработал запрос, то последующие события сязанные с обновлением Кеша и отправкой http ответа модули http аутентификации должны мало интересовать.

              Я не спорю, что будущее за OWIN. Но пока основная веб-технология в стеке ASP.NET не Owin совместима, а Helios в нестабильной alphe и так же не совместим с MVC + Большинство разработчиков, которые хостят под IIS Owin приложение, даже не знают на каком событии httapplication будут вызваны middleware, все это нельзя будет назвать «Отлично работает со всеми фреймворками и универсальная для всего.»
              • 0
                Вы кстати, наверное до сих пор не поняли о чем речь. Думаю полезно будет: www.asp.net/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline.
                Если вы взяли какой-то OWIN Authentication Middleware, который этого не учитывает и вдруг решили использовать вместе с MVC, то у вас потенциально появиться здоровенная дыра в безопасности.

                OWIN универсальный интерфейс, только для технологий совместимых с ним. ASP.NET MVC, WebForms, WebPages в этот список не входят.
                MS самой собой дали инструмент, не имея возможности сделать System.Web совместимым с OWIN, просто наделали кучу костылей, что бы оно завелось с system.web.
                • +1
                  ASP.NET MVC, WebForms в этот список не входят.

                  Все отлично заводится на раз-два с OWIN. Думаю полезно будет: www.asp.net/mvc/tutorials/mvc-5/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on

                  PS: О какой дыре в безопасности речь? Честно, назовите хотя бы один единственный сценарий при котором именно OWin middleware будет слабым звеном в пуле авторизации?
                  • 0
                    Я отвечу дальше.

                    Можно задам встречный вопрос, что бы знать хоть бы понимаете ли вы суть ссылок которые привели и контраргументов, которые здесь малоуместны.

                    Если вы закинули ваше Owin приложение в IIS поверх Katana, в какой момент IIS передаст управление этому OWIN приложению, когда пришел http запрос на сервер?
                • 0
                  ЭЭ вы чего? Какая дыра в безопасности то с MVC?

                  Даже если технология не полностью «совместима»(то есть просит System.Web) — работает на отлично. Просто сделали интеграцию с OWIN через HttpModule. В результате все отлично работает. Где вы нашли проблему — не пойму. Хотите — настройте в каком ивенте вам обрабатывать.

                  Пока я не вижу ни одного аргумента в сторону старых HttpModule's.

                  • 0
                    Пока я не вижу ни одного аргумента в сторону старых HttpModule's.

                    А что я должен аргументировать? Я где-то писал что http module, лучше чем middleware, что вы от меня ждете аргументов? :)

                    Где вы нашли проблему — не пойму

                    Да я и не искал проблем.

                    Вы написали, надо использовать универсальный owin и вообще забыть про http modules и handlers из классического asp.net.

                    Я ответил, что это не совсем так. До сих пор ASP.NET стек можно подружить с middleware только используя реализацию owin от microsoft — Katana, которая все равно имеет дело с http application events и модулями. И если не использовать специфичекую конфигурацию, middleware могут работать неправильно.
                    • 0
                      Ну мой посыл заключался в том, что на данный момент развивать идею модулей — не логично, в силу текущей конъюнктуры. Для текущих проектов это не особо актуально ИМХО, а вот для новых вполне. Там и 4.5+ весьма вероятен и цепляться на старые модули нет смысла.

                      Интеграция с System.Web выполнена в виде HttpModule, но чего-то страшного я здесь не вижу. В последствие можно будет легко убрать этот интеграционный слой и не трогать всю остальную логику. Дефолтные шаблоны приложений дают вполне вменяемый базовый каркас с OWIN MIddleware. Все что нужно — поставить WebHost.
    • 0
      К OWIN дальше и хочу перейти. Сам использую именно его.
  • +1
    А куда пост уехал?
    • +1
      Ошибся адресом, простите.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.