вторник, 22 ноября 2011 г.

Symfony2 Security. Аутентификация.



В последнем проекте пришлось достаточно глубоко покопаться в Security компоненте Symfony2. Это была одна из моих первых задач на этом фреймворке. И, скажу, что я не сразу ощутил всю мощь этого компонента, т.е. сначала было сложно и не понятно. А компонент действительно мощный. С помощью него можно решить, например, такие задачи:
  • Разграничение по ролям зон доступа на сайт. При этом для каждой из зон доступа можно сделать свой механизм аутентификации. К примеру, для обычных пользователей можно сделать вход через twitter и/или facebook, а для доступа в админку использовать локальные пароли из БД или из конфигурационного файла. 
  • Ограничение времени прибывания на сайте (например не более двух часов в день).
  • Временные учетные записи (например, учетная запись, которая действительна до какой-то даты).
  • Учет количества попыток входа на сайт и, например, бан IP-адреса после определенного количества неудачных попыток или дополнительно запрашивать ввод captcha.
  • Блокировка любых диапазонов IP-адресов.
  • Блокировка пользователей по рейтингу, по какому-то балансу,в принципе, можно блокировать доступ по чему угодно.
  • Из коробки доступен производительный ACL (не используется ORM для хранения правил, используются ObjectIdentities вместо самих объектов).
  • Можно использовать любые механизмы аутентификации и легко создавать собственные. Многие из них уже реализованы во множестве бандлов. Например, Максим, сделал бандл для аутентификации через OpenID.
Это далеко не полный список возможностей Security в Symfony2. И практически любая кастомизация, почти любое расширение функционала легко впишутся в общую концепцию, благодаря хорошо продуманному API.


Сегодня напишу несколько строк об аутентификации. 


Итак, весь процесс аутентификации выглядит примерно так:




(Кликабельно)

Я употребил слово "примерно", потому как тут, как и в Symfony в целом, все очень гибко. Если вы захотите изменить этот процесс и заставить систему аутентификации работать иначе, вам не понадобится переписывать полностью всю систему.



1. Token (Токен)


Токен представляет собой абстракцию хранилища данных, идентифицирующих пользователя (User). Токен может находится в аутентифицированном и неаутентифицированном состоянии. Он хранит также список ролей пользователя (Roles) или знает как их получить. Также токен содержит методы для получения и обновления своего состояния (isAuthenticated, setAuthenticated). Можно хранить в токене и разные другие данные в виде аттрибутов (Attributes). Сам  токен не содержит методов для проверки идентификационных данных, за это отвечает провайдер аутентификации (Authentication Provider).


В Symfony уже будут несколько реализаций токенов. К примеру, AnonymousToken, UsernamePasswordToken и др. Лучший путь сделать свой кастомный токен - это унаследовать свой класс от AbstractToken.


2. Authentication Provider (Провайдер аутентификации)


Провайдер аутентификации отвечает за проверку идентификационных данных у пользователя. Чтобы написать свой провайдер аутентификации, вы должны реализовать интерфейс AuthenticationProviderInterface. Или можно унаследовать свой класс от абстрактного класса. AuthenticationProviderInterface описывает два метода: authenticate и supports. Оба метода принимают токен, в качестве  параметра. Метод supports должен вернуть true, если он может обработать предоставленный токен и false в противном случае. Метод authenticate должен вернуть аутентифицированный токен или выбросить AuthenticationException, если токен не удалось аутентифицировать. 
В Symfony уже есть несколько провайдеров аутентификации. К примеру, DaoAuthenticationProvider. Этот  провайдер аутентификации использует другую абстракцию - провайдер пользователей (User Provider). См. ссылки в конце поста, чтобы найти больше информации по провайдерам пользователей.


3. Security Listener (Подписчик)


Подписчик отвечает за получение информации из запроса (Request), создание нужного токена и установку в него идентификационных данных. Также в его задачу входит вызов провайдера аутентификации и передачу в него токена, установку токена в Security Context. А также тут можно сделать обработку исключений аутентификации. Метод handle принимает  объект запроса (Request) и может вернуть аутентифицированный токен или объект ответа (Response). Тут также доступен абстрактный класс AbstractListener. Унаследовав свой  подписчик (Listener) от него, мы сможем избавиться от черновой работы. Нужно будет только реализовать метод attemptAuthentication.


4. Security Factory (Фабрика)


Через фабрику мы объединяем вместе все три предыдущих участника и "рассказываем" о них фреймворку. Тут тоже есть абстрактный класс, реализующий "лишний" функционал. Factory должна быть описана в конфигурации в разделе (security/factories) и помечена тэгом "security.listener.factory".


Это, собственно, и все классы, которые нас интересуют для того, чтобы реализовать свой процесс аутентификации. Остался последний шаг - сконфигурировать файерволлы. Но об этом вы можете прочитать в официальной документации.

Уже существуют множество бандлов, реализующих аутентификацию через twitter, facebook, openid и др. Если же будет необходимость, легко реализовать свой механизм. Например, в моем проекте была аутентификация через удаленный сервер по протоколу SOAP. Также был реализован дополнительный запрос капчи, если удаленный сервер сообщал о необходимости проверить пользователя.

Эта статья получилась небольшой. Но, надеюсь кому-то она окажется полезной.

Несколько ссылок по теме:

Официальная документация по Security в Symfony2 (английский)

Русский перевод официальной документации

Доклад от Johannes Schmitt (видео на английском), отличная презентация от одного из разработчиков Security в Symfony2.

Как сделать кастомный провайдер аутентификации (английский), пример реализации для протокола WSSE.

Справка по конфигурации Security (английский), тут тоже есть кое-что интересное.

Коротенькая статья по созданию Authentication Provider(английский), запомнилась картинкой, которая меня изначально еще больше запутала, чем что-то прояснила.

Статья перевод по Security Component'у на хабре (русский), в ней больше внимания уделено провайдерам пользователей и ролям.



Удачи в освоении Symfony! И ждите в скором времени вторую часть статьи, посвященную авторизации.

2 комментария:

  1. Анонимный05.12.2011, 17:54

    а можно как-то увидеть получившийся код реализации аутентификации через удаленный сервер по протоколу SOAP?

    ОтветитьУдалить
  2. Если есть какие-то конкретные вопросы, вы можете постучать ко мне в скайп: art_kolesnikov

    ОтветитьУдалить