Как правильно оформить кастомную аутентификацию в Symfony2? Сразу оговорюсь, что официальная документация с примером WSSE-аутентификации не очень прояснила мне суть вопроса. Необходимо сделать аутентификацию через метод API сервиса, который внешне похож на OpenID, но им не является. Механика работы аутентификации: 1. Проверка аутентификации пользователя и, если он не аутентифицирован то выдать ему сообщение с предложением пройти на страницу аутентификации. Тут срабатывает мой контроллер, отображающий выбор региона, а потом переадресовывающий пользователя на нужный метод API. 2. На странице он должен будет выбрать один параметр: регион. При клике на кнопку нужного ему региона пользователь попадает вызывает определённый Action контроллера (либо же это правильнее сделать внутри механизма аутентификации, но тогда как и куда редиректить пользователя?), где происходит запрос к API внешнего сервиса нужного региона (регион запоминается) для получения уникальной ссылки аутентификации, после чего пользователь редиректится по этой ссылке, где он должен будет подтвердить передачу сайту данных: токена доступа к API этого самого внешнего сервиса, юзернейма во внешнем сервисе и айдишника там же. Тут непонятно, правильно ли будет делать это в контроллере, или надо переложить это тоже на кастомную аутентификацию? Если надо переложить, то как? После клика по кнопке региона от пользователя до возврата с данными на сайт больше ничего не потребуется. 3. После подтверждения пользователь редиректится обратно на сайт (в первом запросе внешнему API передаётся путь, куда редиректить пользователя), на страницу, которая принимает данные - токен, юзернейм, айдишник. 4. Система аутентификации в Listener'е создаёт токен, записывает в него пришедшие данные и отправляет токен на проверку:protected function attemptAuthentication(Request $request) { if ($request->get($this->options['status_parameter'], null, true) == 'ok') { // Наполнение токена данными return $this->authenticationManager->authenticate($token); } } Тут, к счастью, всё понятно. Разве что, хотелось бы уточнить, когда вызывается метод attemptAtuthentication() у Listener'а. Если только при переходе на адрес, который указан в файрволе как адрес проверки данный - значит я всё правильно понял. 5. В дело вступает кастомный провайдер аутентификации. В методе authenticate() происходит вызов другого метода, который делает запрос ко внешнему сервису для проверки валидности токена (ведь с редиректом можно вернуть фальшивый юзернейм) и, если токен валидный - происходит поиск пользователя с таким юзернеймом, который указан в токене через userProvider:$user = $this->userProvider->loadUserByUsername($token->getUsername()); Если пользователь не существует - его нужно создать и задать ему юзернейм, и параметр айди на внешнем сервисе (не внутренний id, который primary key, а дополнительное поле, которое хранит внешний id).if (!$user) { $user = new User(); $user->setUsername($token->getUser()); //... // Setting role //... } В итоге у нас получается либо новый пользователь, либо найденный в базе. Новому токену задаётся юзер и статус аутентификации:public function authenticate(TokenInterface $token) { // Тут вышеописанная рутина $authenticatedToken->setUser($user); $authenticatedToken->setAuthenticated(true); return $authenticatedToken; }Здесь непонятно то, как можно в методе authenticate() провайдера аутентификации инициировать создание пользователя, ведь это не контроллер и тут просто так не получить менеджер сущностей и отправив нового пользователя на сохранение$em = $this->getDoctrine()->getManager(); $em->persist($user); $em->flush();Наверное, мне нужно каким-то образом передать в конструктор провайдера сервис Doctrine? 6. После этого, по идее, где-то нужно положить текущий токен в контекст безопасности, да и пользователя где-то нужно положить так, чтобы в дальнейшем он был прозрачно доступен по $this->getUser() в контроллерах. Тут непонятно, где конкретно это сделать будет правильно. Или система аутентификации позаботится об этом сама? 7. Ну и как-то после этого процесса нужно опять же выдать свой кастомный ответ в JSON о том, что аутентификация пройдена. P.S. Сейчас имеется токен, который, кажется, реализован правильно. По крайней мере, с ним всё просто и понятно. Ещё имеется Listener унаследованный от AbstractAuthenticationListener. У абстрактного класса в параметрах есть 'login_path'. Я так понимаю, где-то там мне и нужно отображать выбор региона для пользователя, но так как это обрабатывает бандл Security, а не мои контроллеры - я пока не понимаю, как это реализовать. 'check_path' - это, как я понимаю, страница, куда пользователь должен приземлиться после редиректа со стороннего сервиса (в случае с обычной формой логина сюда должны прилетать данные формы, так?). P.P.S. Официальную документацию читал. Там речь о WSSE, у которого другой принцип работы. И эту статью - тоже. Благодаря ним частично разобрался, но всё вышеописанное - пробелы после чтения. Прошу прощения за такой объёмный "вопрос". Подозреваю, что может вскрыться что-то ещё, что я не понял, но если разберусь с вышеописанным механизмом - будет значительно проще разбираться дальше.
Для реализации кастомной аутентификации в Symfony2, в вашем случае, можно применить следующий подход:
Создайте свой собственный провайдер аутентификации, который будет отвечать за проверку валидности токена и создание пользователя (при необходимости). Вы можете передать сервис doctrine в конструктор провайдера для работы с базой данных.
В методе authenticate() вашего провайдера вы можете использовать doctrine для создания нового пользователя и сохранения его в базе данных.
После успешной аутентификации и создания пользователя, вы можете установить текущий токен в контекст безопасности и связать его с пользователем.
Для возврата кастомного ответа в JSON о успешной аутентификации, вы можете создать свой Event Listener, который будет отлавливать событие успешной аутентификации и формировать нужный вам ответ.
Для отображения страницы выбора региона, вы можете использовать событие InteractiveLoginEvent, которое возникает после успешного входа пользователя. В обработчике этого события вы можете сделать редирект на страницу выбора региона.
Необходимо также настроить ваш файл security.yml, указав пути для проверки процесса аутентификации и входа пользователя (логин и проверка аутентификации). Также укажите свой кастомный провайдер аутентификации и Event Listener для обработки событий.
Надеюсь, что эти указания помогут вам с реализацией кастомной аутентификации в Symfony2. Если у вас возникнут дополнительные вопросы, не стесняйтесь задавать их.
Для реализации кастомной аутентификации в Symfony2, в вашем случае, можно применить следующий подход:
Создайте свой собственный провайдер аутентификации, который будет отвечать за проверку валидности токена и создание пользователя (при необходимости). Вы можете передать сервис doctrine в конструктор провайдера для работы с базой данных.
В методе authenticate() вашего провайдера вы можете использовать doctrine для создания нового пользователя и сохранения его в базе данных.
После успешной аутентификации и создания пользователя, вы можете установить текущий токен в контекст безопасности и связать его с пользователем.
Для возврата кастомного ответа в JSON о успешной аутентификации, вы можете создать свой Event Listener, который будет отлавливать событие успешной аутентификации и формировать нужный вам ответ.
Для отображения страницы выбора региона, вы можете использовать событие InteractiveLoginEvent, которое возникает после успешного входа пользователя. В обработчике этого события вы можете сделать редирект на страницу выбора региона.
Необходимо также настроить ваш файл security.yml, указав пути для проверки процесса аутентификации и входа пользователя (логин и проверка аутентификации). Также укажите свой кастомный провайдер аутентификации и Event Listener для обработки событий.
Надеюсь, что эти указания помогут вам с реализацией кастомной аутентификации в Symfony2. Если у вас возникнут дополнительные вопросы, не стесняйтесь задавать их.