Ответ
Интеграция Spring Security с Keycloak позволяет делегировать аутентификацию и авторизацию внешнему OAuth 2.0 / OpenID Connect (OIDC) провайдеру.
Базовая настройка:
-
Добавление зависимостей (Maven):
<!-- Стартер Keycloak для Spring Boot --> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-spring-boot-starter</artifactId> </dependency> -
Конфигурация в
application.yml:keycloak: realm: my-application-realm auth-server-url: ${KEYCLOAK_URL:http://localhost:8080/auth} # URL сервера Keycloak resource: my-spring-backend-client # Client ID в Keycloak public-client: false # Для конфиденциальных клиентов (backend) credentials: secret: ${KEYCLOAK_CLIENT_SECRET} # Секрет клиента ssl-required: external use-resource-role-mappings: true -
Конфигурация безопасности (современный подход без устаревшего адаптера):
import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.web.SecurityFilterChain; @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // Конвертер для преобразования ролей из JWT-токена Keycloak JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter(); jwtConverter.setJwtGrantedAuthoritiesConverter(new KeycloakJwtRolesConverter()); http .authorizeHttpRequests(authz -> authz .requestMatchers("/api/public/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") // Роли из Keycloak .requestMatchers("/api/user/**").hasRole("USER") .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtConverter)) ); // Валидация JWT-токенов через Keycloak return http.build(); } } -
Защита эндпоинта:
@RestController @RequestMapping("/api/user") public class UserController { @GetMapping("/profile") // @PreAuthorize("hasRole('USER')") // Альтернатива конфигурации в SecurityFilterChain public String getUserProfile() { return "User profile data"; } }
Как это работает:
- Клиент (frontend) аутентифицируется в Keycloak и получает JWT-токен (Access Token).
- Клиент отправляет этот токен в заголовке
Authorization: Bearer <token>запроса к Spring Boot приложению. - Spring Security (
oauth2ResourceServer) проверяет подпись токена, извлекает claims (роли, имя пользователя) и создает объект аутентификации. - На основе ролей из токена (
resource_access.<client>.roles) принимается решение о доступе к эндпоинту.
Преимущества: Централизованное управление пользователями и правами, поддержка SSO, стандартные протоколы безопасности.
Ответ 18+ 🔞
А, слушай, смотри, вот эта вся ваша интеграция Spring Security с Keycloak — это, блядь, как делегировать всю свою головную боль по логинам-паролям какому-то внешнему дяде. Типа, «на, ёпта, сам разбирайся, кто тут пользователь, а кто — пидарас шерстяной». И дядька этот — OAuth 2.0 / OpenID Connect провайдер, в нашем случае — Keycloak.
Ну, начинаем колдовать, блядь:
-
Сперва жмакаем в проект нужную хуйню (Maven):
<!-- Вот этот самый стартер, чтобы Keycloak в Spring Boot впендюрился --> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-spring-boot-starter</artifactId> </dependency>Без этого нихуя не взлетит, это как без билета в еперный театр.
-
Потом в
application.ymlпишем заклинание:keycloak: realm: my-application-realm # Твоё королевство в Keycloak auth-server-url: ${KEYCLOAK_URL:http://localhost:8080/auth} # Адрес этого самого дядьки resource: my-spring-backend-client # Твой паспорт (Client ID) public-client: false # Ты не публичная шлюха, а конфиденциальный клиент (backend же!) credentials: secret: ${KEYCLOAK_CLIENT_SECRET} # Секретное слово, типа «сим-сим, откройся» ssl-required: external use-resource-role-mappings: trueГлавное — секрет (
secret) не потеряй, а то любой левый чувак сможет прикинуться твоим бэкендом. Доверия ебать ноль будет. -
Теперь конфиг безопасности (современный, без старых адаптеров, которые уже в утиль):
import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.web.SecurityFilterChain; @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // Вот этот преобразователь — чтобы роли из токена Keycloak вытащить JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter(); jwtConverter.setJwtGrantedAuthoritiesConverter(new KeycloakJwtRolesConverter()); // Свой конвертер для ролей http .authorizeHttpRequests(authz -> authz .requestMatchers("/api/public/**").permitAll() // Сюда пускаем всех, даже кота .requestMatchers("/api/admin/**").hasRole("ADMIN") // Только для избранных .requestMatchers("/api/user/**").hasRole("USER") // Для простых смертных .anyRequest().authenticated() // Всё остальное — только со пропуском ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtConverter)) ); // И вот тут магия: Spring будет проверять JWT-токены через Keycloak return http.build(); } } -
Ну и контроллер, который теперь под защитой:
@RestController @RequestMapping("/api/user") public class UserController { @GetMapping("/profile") // Можно и так: @PreAuthorize("hasRole('USER')") public String getUserProfile() { return "User profile data"; } }Без правильного токена на этот эндпоинт — получишь, вротберунчик, отлуп от Spring Security.
А работает вся эта хуйня так, блядь:
- Какой-то фронтенд (или мобила) идёт, кланяется Keycloak, говорит: «Пусти, я свой». Keycloak его проверяет и выдаёт JWT-токен (это такая цифровая бумажка, что ты — не левый человек).
- Этот фронтенд, довольный как слон, лезет к твоему Spring Boot приложению и суёт эту бумажку в заголовок:
Authorization: Bearer <вот_этот_токен>. - Spring Security его видит и такой: «О, ёклмн, токен!». Он не сам его разбирает, а спрашивает у Keycloak (или проверяет подпись): «Дядь, это твоя работа?». Keycloak кивает. Spring тогда вытаскивает из токена claims — кто ты, какие у тебя роли, и создаёт внутри объект аутентификации.
- И уже по этим самым ролям (
resource_access.<client>.rolesвнутри токена) решает: пускать тебя в/api/adminили послать нахуй с сообщением 403.
И в чём, сука, кайф? А кайф в том, что пользователей и их права теперь не в своей базе душить, а в одном месте — в Keycloak. Single Sign-On (SSO) работает, протоколы стандартные, безопасность. В общем, не еби себе мозг, пусть Keycloak парится.