Часть 1. Legacy code PHP Symfony 2.8. и Keycloak
В жизни значительной части разработчиков рано или поздно появляется тот самый Legacy проект, который приходится изо всех сил поддерживать на плаву. В нашем случае мы столкнулись с проектом на Symfony 2.8 (2015-2019 гг.), который нужно было перевести на новый механизм SSO, а именно - Keycloak
В отличие от более новых версий Symfony, кастомные службы вместе с их зависимостями необходимо регистрировать в конфигурационном файле services.yml. Написанный нами класс KeycloakUserProvider нужно добавить туда.
Поддержка атрибутов (и даже тэгов в phpDoc) в Symfony 2.8 еще не существовала. Поэтому все роуты придется прописать вручную в конфигурационном файле routing.yml. Дополним это еще одним роутом - для возможности выхода из системы с помощью Keycloak. Таким образом, у нас будет три маршрута: connect, check и logout. Два из них придется реализовать в контроллере, один - обмен кода авторизации на токен - возьмет на себя Guard Authenticator (внутренний компонент Symfony).
Если с редиректом на страницу авторизации все относительно просто - нам нужно только вызвать объект из используемой нами библиотеки, а он уже имеет метод с говорящим названием redirect(), то с logout придется повозиться несколько дольше.
Дело в том, что даже сконструировав вручную (не понадобится) URL для деавторизации в Keycloak, приложение оставит внутри себя существующий токен и сессию. Быстро и неочевидно Symfony справится с повторной авторизацией по существующему токену, и пользователь по нажатию кнопки “Выход” просто переадресуется на главную (под капотом же Symfony пошлет запрос не деавторизацию, перейдет обратно, снова вызовет проверку токена и благополучно авторизуется повторно). При хорошем соединении все это произойдет настолько быстро, что пользователь даже не увидит всего этого.
Поэтому в том же методе нам придется реализовать удаление токена из компонента Security. Сделать это можно одной строкой, но необходимо понимать, что наш action будет выполнять параллельно два действия по деавторизации - на стороне клиента (себя) и на стороне сервера (Keycloak).
$this->get('security.token_storage')->setToken(NULL);
Если с переопределением части реализации сторонней библиотеки все было относительно просто, то проблемы взаимодействия двух контейнеров могут вызвать смешанные эмоции. Повторим, что взаимодействие между ними происходит на двух уровнях:
Таким образом, нам нужно, чтобы контейнеры видели друг друга как на машине клиента (в нашем случае на localhost), так и внутри сети Docker. Проблема же заключается в том, что хост для каждого контейнера свой, и в то время как пользователь может подключаться к разным контейнерам через, скажем, разные порты (например, один контейнер может быть доступен на localhost:3000, а другой на localhost:8080), то сами контейнеры знают только один localhost - свой собственный.
Поиск решения этой проблемы занял у нас не один день. В связи с последовательной сменой адресов отваливался то редирект на страницу авторизации, то обмен кода авторизации на токен, то проверка самого токена из-за несовпадения адреса для кого был выдан токен и обращающегося за проверкой приложения.
Выход был найден достаточно простой. Поскольку Keycloak должен быть доступен одновременно и внутри сети контейнеров и вне ее, контейнер был настроен таким образом, чтобы существовать в сети хост-машины. В этом случае он доступен по локальному IP-адресу вида 192.168.х.х в любой ситуации. После этого остается лишь передать в контейнер Symfony этот адрес при сборке либо прописать его вручную в конфигурационных файлах приложения.
Читать далее:
Часть 1. Legacy code PHP Symfony 2.8. и Keycloak
Читать далее:
Часть 1. Legacy code PHP Symfony 2.8. и Keycloak