Привет Хабр! Как известно, spring OAuth2.0.x переведен в режим поддержки уже почти как 2 года назад , а большая часть его функциональности теперь доступна в spring-security (матрица сопоставления). В spring-security отказались переносить Authorization service (roadmap) и предлагают использовать вместо него свободные или платные аналоги, в частности keycloak. В этом посте мы хотели бы поделится различными вариантами подключения keycloak к приложениям spring-boot. Немного о Keycloak Запускаем и настраиваем keycloak Подключаем Keycloak при помощи адаптера Используем OAuth2 Client из spring-security Подключаем приложение как ResourceService Авторизация вызовов сервисов с использованием keycloak Это реализация SSO (Single sign on) с открытым исходным кодом для управления идентификацией и доступом пользователей. Основной функционал, поддерживаемый в Keycloak: Single-Sign On and Single-Sign Out. OpenID/OAuth 2.0/SAML. Identity Brokering – аутентификация с помощью внешних OpenID Connect или SAML. Social Login – поддержка Google, GitHub, Facebook, Twitter. User Federation – синхронизация пользователей из LDAP и Active Directory серверов. Kerberos bridge – использование Kerberos сервера для автоматической аутентификации пользователей. Гибкое управление политиками через realm. Адаптеры для JavaScript, WildFly, JBoss EAP, Fuse, Tomcat, Jetty, Spring. Возможность расширения с использованием плагинов. И многое-многое другое... Для запуска keycloak на машине разработчика удобно использовать docker-compose. В этом случае мы можем в разное время для разных приложений запускать свой сервис авторизации, тем самым избавляя себя от кучи проблем, связанных с конфигурацией под различные приложения. Ниже приведен один из вариантов конфигурации docker-compose для запуска standalone сервера с базой данных postgres: После успешного запуска необходимо произвести настройки realm, клиентов, ролей и пользователей. Произведем некоторые первоначальные настройки. Создадим realm "my_realm": После этого создадим клиент "my_client", через который будем производить авторизацию пользователей (оставим все настройки по-умолчанию): Не забываем указывать redirect_url. В нашем случае он будет равен: http://localhost:8080/* Создадим роли для пользователей нашей системы - "ADMIN", "USER": Добавляем пользователей "admin" с ролью "ADMIN": И пользователя "user" с ролью "USER". Не забываем устанавливать пароли на вкладке "Credentials": Основная настройка закончена, теперь можно приступить к подключению spring boot приложений. В официальной документации к keycloak для использования в приложениях рекомендуют использовать готовые библиотеки - адаптеры, которые дают возможность избавиться от boilerplate кода и излишнего конфигурирования. Есть реализация для большинства популярных языков и фреймворков (supported-platforms). Мы будем использовать Spring Boot Adapter. Создадим небольшое демонстрационное, приложение на spring-boot (исходники можно найти здесь) и подключим к нему Keycloak Spring Boot адаптер. Конфигурационный файл maven будет выглядеть так: Для целей проверки добавим контроллер, который будет выставлять методы для различных ролей пользователей и информацию о текущем пользователе (этот же контроллер мы будем использовать в других примерах ниже): Чтобы наше приложение успешно запустилось и подключилось к keycloak, нам необходимо добавить соответствующую конфигурацию. Первое, что мы сделаем, это в application.yml добавим настройки клиента и подключения к серверу авторизации: После этого добавим конфигурацию spring-security, переопределим KeycloakWebSecurityConfigurerAdapter, поставляемый вместе с адаптером: Теперь проверим работу нашего приложения. Запустим приложение и попробуем зайти пользователем на соответствующий url. Например: http://localhost:8080/api/admin. В результате, браузер перенаправит нас на окно логина пользователя: После ввода корректного имени пользователя и пароля, браузер перенаправит нас на изначальный адрес. В результате получим страницу с некоторой информацией, доступной пользователю: Если перейдем по адресу получения информации о текущем пользователе (http://localhost:8080/api/me), то получим в результате uuid пользователя в keycloak: Если нам нужно, чтобы сервис только проверял токен доступа и не инициализировал процедуру аутентификации пользователя, достаточно включить bearer-only: true в конфигурацию приложения: Использование keycloak адаптера избавляет нас от написания кучи boilerplate кода. Но в то же время наше приложение становится зависимым от реализации. В некоторых случаях не стоит завязываться на какой-то конкретный сервис авторизации, это даст нам больше гибкости в дальнейшей эксплуатации системы. Одной из ключевых особенностей spring security 5 является поддержка протоколов OAuth2 и OIDC. Мы можем использовать OAuth2 клиент из пакета spring-security для интеграции с сервером keycloak. Итак, для использования клиента подключим соответствующую библиотеку в зависимости от проекта (исходный код примера). Полный текст pom.xml: Далее в application.yaml необходимо указать параметры подключения к сервису авторизации: По умолчанию роли пользователей будут вычисляться на основе значения "scope" в access token, и к ним прибавляется "ROLE_USER" для всех авторизованных пользователей системы. Можно оставить как есть и перейти на модель scope. Но в нашем примере мы будем использовать роли пользователей в рамках realm'а. Все, что нам нужно, это переопределить oidcUserService и задать свой маппинг ролей для пользователя. Нужные роли приходят в разделе "groups" токена доступа, его мы и будем использовать для определения ролей пользователя. В результате, наша конфигурация для spring security с переопределенным oidcUserService будет выглядеть так: В данном случае работа приложения будет практически аналогична работе с использованием keycloak адаптера. Довольно часто не нужно, чтобы наше приложение инициировало аутентификацию пользователя. Достаточно лишь проверки авторизации пользователя по предоставляемому токену доступа. Вариантом подключения авторизации с keycloak без использования адаптера является настройка приложения как resource server. В этом случае приложение не может инициировать аутентификацию пользователя, а только авторизует пользователя и проверяет подпись токена доступа. Подключим соответствующие библиотеки: spring-security-oauth2-resource-server и spring-security-oauth2-jose (исходный код). Полный файл pom.xml будет выглядеть так: Далее нам необходимо указать путь к JWK (JSON Web Key) набору ключей, с помощью которых наше приложение будет проверять токены доступа. В keycloak они доступны по адресу: http://${host}/auth/realms/${realm)/protocol/openid-connect/certs. В итоге application.yml будет выгдядеть следующим образом: Как и в случае с OAuth2 Client нам также необходимо переопределить конвертер ролей пользователя. В данном случае мы можем переопределить jwtAuthenticationConverter. Полный текст WebSecurityConfiguration: Здесь мы создаем конвертер (jwtGrantedAuthoritiesConverter), который принимает токен и извлекает из секции "realm_access" роли пользователя. Далее мы можем либо сразу вернуть их, либо, как в данном случае, расширить список, который извлекается конвертером по умолчанию. Проверим работу. Воспользуемся встроенным в Intellij idea http клиентом, либо плагином к VSCode - Rest Client. В начале получим токен пользователя, произведем запрос к keycloak, используя логин и пароль зарегистрированного пользователя: Ответ будет примерно следующего содержания: Теперь проверим, что методы доступны пользователю с соответствующими правами: В ответ получим: При работе с  микросервисной архитектурой иногда возникают требования авторизованных вызовов между сервисами. В случаях, когда инициатором взаимодействия является какой-то внутренний процесс или служба, нам где-то нужно брать токен доступа. В качестве решения данного вопроса мы можем использовать Client Credentials Flow, чтобы получить токен из keycloak (исходный код примера доступен по ссылке). Для начала создадим нового клиента, под которым будут авторизоваться наши сервисы: Для возможности авторизации сервиса нам нужно изменить тип доступа ("Access Type") на "confidential" и включить флаг "Service accounts Enabled". В остальном конфигурация не отличается от конфигурации по умолчанию: Если нам необходимо, чтобы у сервисов, авторизованных под данным клиентом, была своя роль, добавим ее в роли: Далее эту роль необходимо добавить клиенту. На вкладке "Service Account Roles" выбираем необходимую роль -  в нашем случае роль "SERVICE": Сохраняем client_id и client_secret для дальнейшего использования в сервисах для авторизации: Для демонстрации создадим небольшое приложение, которое будет получать информацию доступную по адресу http://localhost:8080/api/service из предыдущих примеров. Для начала создадим компонент, который будет авторизовывать наш сервис в keycloak: Метод authenticate производит вызов к keycloak и в случае успешного ответа возвращает объект KeycloakAuthResponse: Далее мы берем access_token из ответа для того, чтобы использовать в дальнейших вызовах к защищенным методам. Ниже пример вызова к защищенному методу: Сначала мы авторизуем наш сервис через keycloak,  потом производим запрос к защищенному ресурсу, добавив в HTTP Headers параметр Authorization: Bearer ... В результате выполнения программы мы получим содержимое защищенного метода: Конечно, представленный в примере выше строго в ознакомительных целях KeycloakAuthClient нельзя использовать в продуктовой среде, как минимум нужно добавить поддержку сохранения токена доступа на некоторое время, а еще лучше поддержку механизма обновления токена доступа при истечении его срока действия. Подключение keycloak с помощью поставляемого адаптера, конечно, избавляет нас от написания большого количества кода и конфигураций. Но тогда наше приложение будет завязано на конкретную реализацию сервиса авторизации. Подключение же с использованием только возможностей фреймворка spring дает нам больше гибкости в настройке и больше выбора в реализациях. Но вместе с тем заставляет нас писать больше кода и конфигурации, хотя, на мой взгляд, не настолько уж много. В любом случае, при выборе, как подключать сервис авторизации к своему приложению, мы должны исходить из множества параметров, главным из которых является здравый смысл. Спасибо за внимание! UPD: По созданию расширений в keycloak, можно почитать в статье у моего коллеги java/javascript developer