Обособленная аутентификация через Вконтакте посредствам SSO на SpringSecurity

Обособленная аутентификация через Вконтакте посредствам SSO на SpringSecurity

Я создал отдельный сервис SSO аутентификации 🔐
чтобы собрать воедино всю аутентификацию и авторизацию многочисленных микросервисов проекта в одном месте. Однако, перенести всю локальную авторизацию в SSO не так-то просто и требует глубокого осмысления пути интеграции. Поэтому пока я морально к этому не готов и отложил это занятие на потом 😌

В то же время обнаружилось, что авторизация Вконтакте перестала работать ❌ оказалось, что тот способ с неограниченными access_token’ми вконтакт признал устаревшим и теперь он перестал работать. Возникла острая необходимость срочно переписывать подход на новые рельсы 🚨

Здесь как-раз очень удачно появился SSO, т.к. там аутентификация через ВК написана с новым подходом

Однако, SSO позволяет авторизовываться не только через ВК, но и через Email, Яндекс, Google и Github. И теперь мне нужно как-то чтобы заставить пользователя авторизоваться именно через Вконтакте 🤯

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

В итоге решил реализовать обособленный поток аутентификации, который и будет выполнять мою задачу 🧵


Задачи обособленного потока:

🔹 аутентифицироваться только через выбранного провайдера (в данном случае ВК), без выбора других вариантов
🔹 текущая сессия пользователя в SSO не должна быть нарушена, даже если по обособленной аутентификации вошел другой пользователь
🔹 реализация общения с ВК (получение code, обмен на access_token) должна быть спринговая, т.е. нужно как-то задействовать текущий flow, но вовремя его оборвать, не затереть текущую сессию
🔹 если текущая сессия пользователя в SSO имеет привязку к аккаунту ВК, показывать пользователю страницу с вариантами выбора: либо войти как текущий пользователь, либо войти как другой пользователь


Взаимодействие должно выглядеть таким образом:

🔗 Отправляем пользователя ссылку инициализации

1
/api/separate-auth/init?provider=vkontakte&client_id=test-client&redirect_uri=http://localhost:8080/separate-auth-result

🎯 Ожидаем результат по адресу

1
http://localhost:8080/separate-auth-result?userId=SIME_USER_UUID


Итак, искал множество подходов для реализации, пробовал варианты, мучал нейросеть и ковырялся в документации. В итоге пришел к такому решению:

1️⃣ При заходе на ссылку инициализации, смотрим есть ли текущая сессия в SSO с привязанным аккаунтом ВК, и отправляем пользователю 302 редирект либо на страницу выбора пользователя, либо прямиком в авторизацию Вконтакта

2️⃣ Также немного модифицирую ссылку авторизации Вконтакта, добавляем query параметр, в котором указываем, что данная авторизация должна быть в обособленном режиме (пример: https://mysso.site/oauth2/authorization/vkontakte?separate=SEPARATE_UUID)

3️⃣ Написал свою реализацию OAuth2AuthorizationRequestResolver, в которой как-раз вытягиваю этот SEPARATE_UUID и сохраняю в authorizationRequest.additionalParameters. Теперь в рамках всего flow будем его знать

4️⃣ Далее работает уже написанная логика авторизации ВК на спринговых OAUTH2 классах. В конце авторизации генерируется эвент успеха. Он мне и нужен, т.к. это происходит до записи новой авторизации в securityContextHolder

5️⃣ Пишу @EventListener на AuthenticationSuccessEvent, извлекаю SEPARATE_UUID, access_token Вконтакта, идентификатор пользователя в SSO и внаглую кидаю эксепшн кастомного класса 💥

6️⃣ Всё раскручивается обратно и авторизация падает, но есть одна хитрость — я зарегистрировал кастомный OncePerRequestFilter и воткнул его прям перед OAuth2LoginAuthenticationFilter. Этот фильтр просто перехватывает моё кастомное исключение, останавливает дальнейшее раскручивание stack-trace, и делает 302 response.sendRedirect пользователю 🎯


Красиво? Мне кажется весьма неплохо 😎
Все задачи обособленного потока выполнены, и максимально использована спринговая реализация потоков ✅

Скоро интегрирую решение в CRM и можно будет настраивать автоматическую выгрузку ассортимента на витрину Вконтакте💪

(Просмотрено 1 раз, 1 раз за сегодня)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *