Введение
Данная статья является инструкцией для новичков, которые хотели бы использовать Keycloak в своих проектах в качестве безопасности. В статье будет рассказано:
Что такое Keycloak и для чего он нужен.
Как запустить Keycloak.
Как создать свой первый realm.
Как настроить Keycloak.
Как интегрировать Keycloak в свое приложение на Spring.
В данной статье не будет подробного изучения данного сервера. Я разберу основные моменты, которые нужно знать, чтобы начать использование.
Keycloak
Для начала разберемся для чего нужен keycloak.
Keycloak — это система управления доступом с открытым исходным кодом, которая позволяет добавлять аутентификацию и авторизацию в приложения и сервисы. Она предоставляет функции единого входа (SSO), а также поддерживает различные протоколы аутентификации, такие как OpenID Connect, OAuth 2.0 и SAML.
Основные возможности Keycloak:
Единый вход (SSO): позволяет пользователям входить в систему один раз и получать доступ ко всем связанным приложениям без повторной аутентификации.
Социальная аутентификация: поддержка интеграции с социальными сетями, такими как Google, Facebook, Twitter, для аутентификации пользователей.
Централизованное управление пользователями: администраторы могут управлять пользователями, ролями и разрешениями из единого интерфейса.
Поддержка различных протоколов: как упоминалось ранее, Keycloak поддерживает множество стандартных протоколов аутентификации и авторизации.
Настраиваемая и расширяемая: возможности платформы можно расширить за счет использования различных плагинов и адаптеров.
Интеграция с LDAP и Active Directory: возможность интеграции с существующими системами управления пользователями.
Keycloak часто используется в больших организациях и проектах, требующих надежной и масштабируемой системы управления доступом.
Запуск Keycloak
Для начала создадим наш проект Spring, для этого можно использовать открытый для всех spring initializer - https://start.spring.io/ или же, если есть IntelliJ IDEA Ultimate, то можно создать проект Spring прям в ней.
Добавим нужные зависимости и создадим проект:
После того, как наш проект сформируется, у нас появится файл pom.xml, в котором будут прописаны все наши зависимости:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>OauthTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>OauthTest</name>
<description>OauthTest</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Для дальнейшего использования Keycloak нам нужно прописать еще одну зависимость. Для того чтобы найти нужную зависимость и актуальную версию, можно использовать сайт - https://mvnrepository.com/
<!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-admin-client -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>26.0.2</version>
</dependency>
Чтобы запустить keycloak, я буду использовать Docker. Для этого создадим в корневой папке нашего проекта файл docker-compose.yml и пропишем в нем загрузку образов и создание контейнеров. Также я буду использовать вместо базы данных H2, которая установлена по-умолчанию в keycloak, базу данных posgreSQL, которую также запустил в Docker и подключил к keycloak.
docker-compose.yml
services:
postgres:
container_name: Postgres
image: postgres
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
POSTGRES_DB: keycloak
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- 5435:5432
networks:
- keycloak-network
restart: unless-stopped
keycloak:
container_name: Keycloak
image: quay.io/keycloak/keycloak:latest
ports:
- 9090:8080
environment:
DB_VENDOR: POSTGRES
DB_ADDR: postgres
DB_DATABASE: keycloak
DB_SCHEMA: public
DB_USER: root
DB_PASSWORD: root
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
networks:
- keycloak-network
depends_on:
- postgres
command:
- "start-dev"
networks:
keycloak-network:
driver: bridge
volumes:
postgres_data:
driver: local
keycloak:
driver: local
Наш keycloak будет работать на порту 9090. После запуска контейнера мы можем перейти на наш сервер по ссылке http://localhost:9090. Для того, чтобы войти в настройки keycloak, нам нужно вести данные, которые мы указали при создании контейнера.
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
Keycloak запущен, можно приступать к настройкам.
Настройка Keycloak
После входа, нам нужно создать наш realm. Realm (область) — это пространство, которое управляет набором пользователей, учетных данных и ролей. Реалмы позволяют изолировать данные и настройки, чтобы различные приложения и пользователи могли существовать в одном экземпляре Keycloak без пересечения данных.
Создание нового realm
После создания нашего realm нам нужно создать нового client. Для этого переходим в раздел Clients и нажимаем кнопку Create client.
Создание своего Client
Даём имя нашему client.
Устанавливаем в Client authentication флаг на On.
Прописываем наши URL.
Данный URL будет использовать наш бэк. В дальнейшем мы это все пропишем.
После того как мы создали нашего client, создадим нового пользователя (User). Для этого перейдем во вкладку Users. Здесь нам нужно создать пользователя, указав логин и пароль.
Создание нового пользователя
Пропишем данные в полях.
После создания, данный пользователь не будет иметь пароля, для это установим его во вкладке Credentials.
Теперь у нас есть пользователь в базе данных. Давайте проверим можно ли войти под этими данными. Для этого создадим файл scratch.http и пропишем следующее:
POST http://localhost:9090/realms/OauthTests/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
client_id=myclient&client_secret=SECRET&username=kudzip&password=test&grant_type=password
client_id - это название, созданного нами client.
client_secret - это секретный ключ нашего client, его можно скопировать следуя инструкциям в пункте Копирование client secret. Данный ключ нужно вставить вместо слова SECRET.
Копирование client secret
username и password - это username и password, созданного нами пользователя.
После отправления запроса нам в ответ генерируется access_token и refresh_token:
Данный запрос можно выполнить в postman.
Как видно из изображения, все работает исправно. Проверим данный токен на сайте - JWT.IO.
Данный токен несет в себе основную информацию о пользователе. В поле "полезная нагрузка" можно увидеть все нужные данные. (email, role, name, family, username и тд.)
Во вкладке Clients можно посмотреть какую информацию у нас будет хранить JWT. Давайте на это посмотрим. Для этого нужно перейти во вкладку Clients и нажать на созданный нами myclient.
Просмотр токена
В поле Users нужно выбрать интересующего нас пользователя.
{
"exp": 1733502948,
"iat": 1733502648,
"jti": "85cd30db-8b48-49a0-bf91-45a8e649e20a",
"iss": "http://localhost:9090/realms/OauthTests",
"aud": "account",
"sub": "4b65107a-99f2-49dc-a161-e12bf2fdc1f3",
"typ": "Bearer",
"azp": "myclient",
"sid": "70a67a84-f849-4b43-a3f8-b5d42b1f4daa",
"acr": "1",
"allowed-origins": [
"http://localhost:8083"
],
"realm_access": {
"roles": [
"default-roles-oauthtests",
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid profile email",
"email_verified": true,
"name": "ivan Storozhev",
"spring_sec_roles": [
"default-roles-oauthtests",
"offline_access",
"uma_authorization"
],
"preferred_username": "kudzip",
"given_name": "ivan",
"family_name": "Storozhev",
"email": "test@test.ru"
}
Такую же информацию мы получили, когда расшифровали наш JWT на сайте.
Для чего нужны Access и Refresh токены?
Они служат для управления доступом к ресурсам и поддержания сеансов пользователей.
Access-токен
Предоставление доступа: Access-токен предоставляет клиентскому приложению права доступа к защищённым ресурсам от имени пользователя или сервиса. Он содержит информацию о пользователе и правах доступа.
Краткосрочный срок действия: Обычно имеют короткий срок действия (несколько минут или часов) для снижения риска компрометации.
Использование в API-запросах: Access-токены передаются в заголовках запросов к API, чтобы сервер мог подтвердить, что запрос авторизован.
JSON Web Tokens (JWT): Часто реализуются в формате JWT, что позволяет серверам быстро проверять подпись и данные токена без дополнительного обращения к серверу авторизации.
Refresh-токен
Обновление access-токена: Refresh-токен используется для получения нового access-токена, когда старый истекает, без необходимости повторной аутентификации пользователя.
Долгосрочный срок действия: Имеют более длительный срок действия по сравнению с access-токенами (дни или недели), что позволяет поддерживать долгосрочные сеансы.
Хранение и безопасность: Должны храниться надежно, так как компрометация refresh-токена может позволить злоумышленнику получать новые access-токены без ведома пользователя.
Не передаются с каждым запросом: В отличие от access-токенов, refresh-токены не используются в обычных API-запросах, а только для обновления access-токенов.
Вместе эти токены обеспечивают баланс между безопасностью и удобством, позволяя пользователям оставаться авторизованными в течение длительного времени, но минимизируя риски, связанные с компрометацией токенов.
Иногда нужно добавить определенную роль, чтобы доступ к странице был только для ограниченных пользователей. Такое можно сделать во вкладке Realm roles. Я добавлю роль менеджера "ROLE_MANAGER".
Создание новой роли
Теперь у нас есть отдельная роль для менеджеров. В конфиге spring security мы пропишем безопасность с учетом ролей.
Подключение авторизации и регистрации через сторонние API. Технология Oauth достаточно удобна и популярна, ее используют сейчас практически везде и с помощью Keycloak, можно подключить авторизацию и регистрацию через Google, GitHub и др. сервисы. Я воспользуюсь API только Google и GitHub. Давайте посмотрим как это сделать.
Чтобы подключить Google нужно перейти на сайт с API. Здесь нам нужно создать новый Oauth client ID.
Откроется окно по созданию client. Первым делом нам нужно выбрать тип приложения (я выбрал Web application). Далее нужно дать имя нашему client. После нужно указать Redirect URI. Как получить Redirect URI описано в пункте Получение Redirect URI.
Получение Redirect URI
После нажатия на "Add provider" будет выбор из нескольких провайдеров, нам нужно выбрать Google.
Когда мы создали наш Oauth client ID, нужно зайти в него, чтобы узнать Client ID и Client secret.
Нам нужно скопировать эти 2 поля и перейти к Keycloak. Здесь нам нужно во вкладке, где мы копировали Redirect URI вставить недостающие поля.
Client ID - скопированный Client ID с API Google.
Client Secret - скопированный Client Secret с API Google.
GitHub
Чтобы подключить GitHub нужно перейти на сайт Developer settings. Здесь нам нужно создать new Oauth app.
Далее заполняем поля.
Получение Redirect URI
После нажатия на "Add provider" будет выбор из нескольких провайдеров, нам нужно выбрать GitHub.
Заходим в созданный нами Oauth app, чтобы узнать Client ID и Client secret.
Нам нужно скопировать эти 2 поля и перейти к Keycloak. Здесь нам нужно во вкладке, где мы копировали Redirect URI вставить недостающие поля.
Client ID - скопированный Client ID с GitHub.
Client Secret - скопированный Client Secret с GitHub.
Настройка Keycloak в Spring
Этот модуль посвящен интеграции Keycloak в Spring приложение.
Для начала нужно прописать свойства в application.yml. Здесь будет указываться, что мы используем в качестве ресурс сервера и клиента наш Keycloak.
application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:9090/realms/OauthTests
client:
provider:
keycloak:
issuer-uri: http://localhost:9090/realms/OauthTests
user-name-attribute: preferred_username
registration:
keycloak:
client-id: myclient
client-secret: YOUR SECRET
scope: openid
server:
port: 8083
logging:
level:
org.springframework.security: TRACE
client-id - это client id, созданного нами client в Keycloak.
client-secret - это секретный ключ, созданного нами client в Keycloak. (Мы его использовали выше, для теста пользователя)
Далее нам нужно создать класс SecurityConfig, чтобы настроить доступ к URI и реализовать oauth2 Resource Server. Это прописывается в методе securityFilterChain.
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/error").permitAll()
.requestMatchers("/manager.html").hasRole("MANAGER")
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
)
.oauth2Login(Customizer.withDefaults());
return http.build();
}
}
@Configuration: Указывает, что класс содержит определения бинов и может быть использован контейнером Spring для генерации бинов.
@EnableWebSecurity: Включает поддержку безопасности веб-приложений в Spring Security.
authorizeHttpRequests: Определяет правила авторизации для HTTP-запросов.
.requestMatchers("/error").permitAll(): Позволяет доступ ко всем запросам на /error
без аутентификации.
.requestMatchers("/manager.html").hasRole("MANAGER"): Разрешает доступ к /manager.html только пользователям с ролью MANAGER.
.anyRequest().authenticated(): Все остальные запросы требуют аутентификации.
oauth2ResourceServer: Настраивает приложение как OAuth2 ресурсный сервер, используя JWT для проверки токенов.
.jwt(Customizer.withDefaults()): Указывает на использование JWT с настройками по умолчанию.
oauth2Login: Включает OAuth2 логин с настройками по умолчанию, позволяя пользователям входить в систему с помощью провайдера OAuth2.
Далее создадим метод jwtAuthenticationConverter. Он конвертирует JWT в объект аутентификации, позволяя извлекать и преобразовывать роли из токена.
jwtAuthenticationConverter()
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtAuthenticationConverter.setPrincipalClaimName("preferred_username");
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
var authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
var roles =jwt.getClaimAsStringList("spring_sec_roles");
return Stream.concat(authorities.stream(),
roles.stream()
.filter(role -> role.startsWith("ROLE_"))
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast))
.toList();
});
return jwtAuthenticationConverter;
}
.setPrincipalClaimName("preferred_username"): Указывает, что preferred_username
будет использоваться как имя пользователя.
jwtGrantedAuthoritiesConverter: Конвертирует роли из JWT в объекты GrantedAuthority
.
roles: Извлекает роли из токена, находящегося в поле spring_sec_roles
.
Stream.concat: Объединяет роли из токена и стандартные авторитеты, преобразуя их в список авторитетов.
oAuth2UserService()
@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oAuth2UserService() {
var oidcUserService = new OidcUserService();
return userRequest -> {
var oidcUser = oidcUserService.loadUser(userRequest);
var roles = oidcUser.getClaimAsStringList("spring_sec_roles");
var authorities = Stream.concat(oidcUser.getAuthorities().stream(),
roles.stream()
.filter(role -> role.startsWith("ROLE_"))
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast))
.toList();
return new DefaultOidcUser(authorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
};
}
OidcUserService: Сервис для обработки аутентификации OpenID Connect.
roles: Извлекает роли из аутентификационного ответа OpenID Connect.
Stream.concat: Объединяет роли из OpenID Connect и стандартные авторитеты, создавая новый объект DefaultOidcUser
с обновленным списком авторитетов.
Целый код класса SecurityConfiig.
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/error").permitAll()
.requestMatchers("/manager.html").hasRole("MANAGER")
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
)
.oauth2Login(Customizer.withDefaults());
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtAuthenticationConverter.setPrincipalClaimName("preferred_username");
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
var authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
var roles =jwt.getClaimAsStringList("spring_sec_roles");
return Stream.concat(authorities.stream(),
roles.stream()
.filter(role -> role.startsWith("ROLE_"))
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast))
.toList();
});
return jwtAuthenticationConverter;
}
@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oAuth2UserService() {
var oidcUserService = new OidcUserService();
return userRequest -> {
var oidcUser = oidcUserService.loadUser(userRequest);
var roles = oidcUser.getClaimAsStringList("spring_sec_roles");
var authorities = Stream.concat(oidcUser.getAuthorities().stream(),
roles.stream()
.filter(role -> role.startsWith("ROLE_"))
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast))
.toList();
return new DefaultOidcUser(authorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
};
}
}
На этом самая базовая настройка Keycloak закончена. Теперь мы можем перейти к тестам.
Тестирование
Для проверки создадим две html страницы. Первая страница будет доступна для всех авторизированных пользователей authenticated.html, а вторая будет видна только менеджерам manager.html. Это сделано для того, чтобы протестировать, работает ли разделение по ролям.
authenticated.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h2>Привет, аутентифицированный пользователь</h2>
</body>
</html>
manager.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h2>Hi manager</h2>
</body>
</html>
Далее запустим наш проект и перейдем на наш хост - http://localhost:8083.
Как видно, нас сразу же перебрасывает на форму авторизации Keycloak. В этой форме есть вход через username/email, а также через GitHub и Google. Попробуем войти под нашим пользователем.
Мы смогли зайти под нашим пользователем. Так как мы создали authenticated страничку, то давайте попробуем туда зайти, указав такой URI - http://localhost:8083/authenticated.html.
Попробуем зайти на страничку manager.
Как видно, мы не можем туда зайти из-за ограничений в доступе, так как у нашего пользователя нет роли менеджер.
Давайте присвоим ему эту роль. Для этого в Keycloak зайдем во вкладку Users и выберем нашего пользователя.
Далее выбираем фильтр "by realm roles" и тут выбираем нашу роль, которую мы создали ранее. Все, новая роль присвоена пользователю. Перезапустим приложение и попробуем войти заново на страничку менеджера.
Как видно, все работает!
Теперь проверим вход и регистрацию через Google и GitHub.
Так как мы не сделали страничку выхода, то сессию нужно завершить в самом Keycloak и перезапустить наше приложение. В Keycloak переходим во вкладку Users, выбираем нашего пользователя, переходим в сессии и завершаем их все.
Далее вновь заходим на наш хост и в форме авторизации выбираем Google.
Далее выбираем наш аккаунт.
Как видно, все работает! Если зайти в Keycloak во вкладку Users, то мы увидим, что у нас добавился новый пользователь.
GitHub
Далее вновь заходим на наш хост и в форме авторизации выбираем GitHub.
Далее вводим наши данные от аккаунта.
Как видно, все работает! Если зайти в Keycloak во вкладку Users, то мы увидим, что у нас добавился новый пользователь.
Из тестирования видно, что все работает. Авторизация проходит по логину и паролю, а также через Google и GitHub.
Вывод
В данной статье я описал, как начать свою работу с Keycloak и интегрировать его в свой проект Spring. Я разобрал главные моменты:
Создание своего realm.
Создание нового client.
Создание своей роли.
Подключение сторонних API.
Данная инструкция поможет освоить Keycloak.
Комментарии (18)
Raspy
07.12.2024 09:48Жаль что в основном статьи для новичков. Что-то посложнее уже почти никто не разбирает. Например всякие аутентификации с помощью физического токена, керберос, по сертификату или северная аутентификация по mTLS без кредов ну и тд и пт. Рассмотрение цепочек аутентификаций с несколькими факторами, в том числе с проверкой сети, подтверждение по смс, устройства, биометрия..
ivan_storozhev Автор
07.12.2024 09:48Спасибо за ваш комментарий!
Я с вами полностью согласен, в наших реалиях действительно больше статей для новичков, но многие технологии все равно разобраны не так детально, как это попытался сделать я. Когда я сам изучал Keycloak, я столкнулся с проблемой, что многие упускают важные детали, которых мне не хватало для полного понимания.
В дальнейшем я планирую делать более подробные статьи, которые касаются не только новичков, но и специалистов с опытом!
Smerig
07.12.2024 09:48Все, что касается этой статьи, описано тут https://www.keycloak.org/docs/latest/authorization_services/index.html.
Smerig
07.12.2024 09:48Лучше напишите какую-нибудь достаточно серьезную статью. С базовыми настройками любой разберется. Либо предложите какое-нибудь неочевидное решение. Или как вы решаете проблему доступа к конкретным ресурсам, допустим, их у вас тысячи. Таскаете ли вы их все в RPT или у вас там только последние N штук. А сколько N штук лучше всего хранить в токене?
ivan_storozhev Автор
07.12.2024 09:48Спасибо за ваш комментарий!
С тем, что тут описаны базовые настройки, я соглашусь, а точнее я прямым текстом в статье об этом пишу. Вы скинули ссылку на документацию по Keycloak, я ее просто упростил и показал все на примерах, чтобы начинающие специалисты быстрее разобрались с этой технологией. Я согласен с вами, что более серьезную статью тоже надо написать, но я бы хотел к этому подойти постепенно. Я хочу, чтобы мои статьи приносили пользу как для начинающих, так и для опытных специалистов, и чтобы каждая статья могла дополнить новую! Еще раз спасибо за ваш комментарий!
LeonidIvanov123
07.12.2024 09:48Не очень понял, для чего используется зависимость
<artifactId>keycloak-admin-client</artifactId>?
Судя по статье - зависимость не нужна.
ivan_storozhev Автор
07.12.2024 09:48Да, вы правы, данная зависимость никак не используется в данной статье, однако, если вы хотите настраивать Keycloak под себя, то она потребуется. Возможно в последующих статьях я про это расскажу, а пока что эту зависимость можно не прописывать. Спасибо за ваш комментарий !
TldrWiki
При изменении политики доступа (добавить роли доступ к эндпойнту) придется менять код. Для этих целей на эндпойнту навешиваются ресурсы. Ресурсы также привязываются к роли. В этом случае достаточно добавить/удалить ресурс в роли для изменения политики доступа.
Но здесь у Кейклоака начинаются сложности. Связаны они с миграцией (необходимость переноса на новый сервер уже настроенной конфигурацией) раз. Со сложностью получения ресурсов из ролей на стороне бека (не проще ли использовать для этого собственное решение) два. И с использованием на фронте (официальная библиотека не поддерживает авторизацию).
ivan_storozhev Автор
Спасибо за ваш комментарий! Это действительно важные вопросы, которые возникают при использовании Keycloak в реальных условиях.
1. Миграция конфигурации: Да, перенос настроек Keycloak на новый сервер сложный процесс. Один из подходов к решению этой проблемы — использование инструментов для автоматизации миграции, таких как Keycloak Export/Import или Terraform для описания инфраструктуры в виде кода. К сожалению, я пока что с этим не сталкивался, поэтому никак не описывал данную проблему, да и данная статья больше подходит для начинающих, которые недавно узнали о keycloak.
2. Получение ресурсов из ролей на бэкенде: В некоторых случаях разработка кастомного решения может быть более эффективной, особенно если ваши требования отличаются от типичных сценариев использования Keycloak. Однако, при этом важно учитывать время и ресурсы, которые понадобятся на разработку и поддержку такого решения. В дальнейшем, я могу написать статью, где буду использовать кастомную реализацию!
3. Использование на фронте: Ограниченная поддержка Keycloak для авторизации на фронтенде может стать проблемой, особенно если вы используете технологии, которые официальная библиотека не поддерживает. В таких случаях можно рассмотреть использование сторонних библиотек или даже разработку собственного решения, которое будет интегрироваться с Keycloak через его API. Я не особо знаком с фронтом, поэтому также не стал затрагивать эту область!
Smerig
Фронт нужен только лишь для того, чтобы обращаться к своему ресурс серверу с передачей RPT (requesting party token). Тут и появляется главное предназначение keycloak - UMA (user managed access). Использование Keycloak в качестве authorization server - это, по моему, больше вспомогательная роль. Т.к. наверняка на рынке есть куча подобных решений.
TldrWiki
Вот именно этот механизм в новых версиях Кейклоака сломан. Чтобы фронт не палил secret сделана возможность аутентификации через публичного клиента. Полученный от публичного клиента токен фронт отправляет беку и бек идет обменивать его на приватный токен с ресурсами (в приватном клиенте) и получает ошибку.
Smerig
Тут вступает в силу UMA. Вы с токеном с публичного клиента идете в бек, бек идет в keycloak с запросом ресурса, получает permission ticket и возвращает его на фронт. Фронт берет тикет и обменивает его на новый токен, уже RPT. И уже с этим RPT идет на бек.
Возможно вы имели в виду то же самое. Но тогда я не понимаю, чего там сломано. Прямо сейчас делаю эту процедуру в Keycloak 26.
ivan_storozhev Автор
После некоторого блока статей, я вернусь к этой теме и постараюсь также детально разобрать этот случай. Спасибо за ваш комментарий !!
TldrWiki
Я уже все грабли сломал. То что вы описываете это для одного ресурса? То есть при каждом запросе бек идет за permission ticket?
У меня другая ситуация. Я пытаюсь обменять публичный токен на rpt со всеми ресурсами, чтобы каждый раз не ходить за токеном. И до 22 версии это работало, но потом перестало.
Smerig
для меня тоже интересен вариант, когда ресурсов тысячи. Но, как я понял, ресурсы можно в токен дописывать. Допустим, штук 50, мне кажется, в токене будет ненапряжно таскать. В общем, прочитайте, тут найдете ответы на все вопросы https://www.keycloak.org/docs/latest/authorization_services/index.html. Пока я целиком не прочитал, рабочего варианта получить не мог.
DMY
Класс, уже не только стати но и ответы пишут с помощью чатгпт
Smerig
не стоит полагаться на чатгпт в вопросе keycloak, многое приходится делать по-другому.
ivan_storozhev Автор
В самой статье данный ресурс никак не был задействован, все писалось самостоятельно на основе личного опыта. Ответ на комментарий действительно отчасти был сгенерирован при помощи гпт, но это было сделано из-за спешки, так как не хотелось оставлять пользователя без ответа. Больше таких ответов как можете заметить нет. Хотелось бы извиниться за такой неприятный случай!