Ответ
Интеграция 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, стандартные протоколы безопасности.