/
Al
/
TESamples
Обзор
Документация
Войти
/
Al
/
TESamples
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
apps/spring/chain-service/src/main/java/com/tokenexchange/service/SecurityConfig.java
89 строк
4 KB
Al
Initial Commit
11 май 2026, 17:40
11 май 2026, 17:40
0a04577
Код
Авторство
О чём код?
package com.tokenexchange.service; import com.tokenexchange.lib.RevocationCache; import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.jwt.JwtDecoders; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver; import org.springframework.security.web.SecurityFilterChain; import org.springframework.web.client.RestClient; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * Конфигурация валидации JWT через Spring Security OAuth2 Resource Server. * Принимает токены, выпущенные ЛЮБЫМ из issuer'ов из {@code KC_TRUSTED_ISSUERS} * (несколько realms одного Keycloak или несколько Keycloak-инстансов в режиме * отказоустойчивости). Если переменная не задана — fallback на единственный * issuer-uri из {@code spring.security.oauth2.resourceserver.jwt.issuer-uri}. * * <p>Применяемые библиотеки: Nimbus JOSE JWT (под капотом у Spring Security). * Никаких самописных парсеров. JWKS подтягивается из * {@code GET /realms/{realm}/.well-known/openid-configuration} → * {@code jwks_uri}, кешируется внутри {@link JwtAuthenticationProvider}; * ротация ключей в Keycloak подхватывается автоматически. * * <p>Связанные разделы Рекомендаций для клиента: * <ul> * <li>§9 «Расхождение часов» — допуск настраивается на стороне валидатора * (docs/client-recommendations.md#9)</li> * </ul> */ @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain( HttpSecurity http, @Value("${KC_TRUSTED_ISSUERS:}") String trustedIssuers, @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") String legacyIssuer ) throws Exception { String[] issuers = trustedIssuers.isBlank() ? new String[]{legacyIssuer} : trustedIssuers.split(","); // Карта issuer -> AuthenticationManager (один на realm; JWKS кешируется внутри). Map<String, AuthenticationManager> managers = new HashMap<>(); Arrays.stream(issuers) .map(String::trim) .filter(s -> !s.isEmpty()) .forEach(iss -> { var decoder = JwtDecoders.fromIssuerLocation(iss); var provider = new JwtAuthenticationProvider(decoder); managers.put(iss, provider::authenticate); }); var resolver = new JwtIssuerAuthenticationManagerResolver(managers::get); http .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .csrf(c -> c.disable()) .authorizeHttpRequests(a -> a .requestMatchers("/actuator/**").permitAll() .anyRequest().authenticated()) .oauth2ResourceServer(o -> o.authenticationManagerResolver(resolver)); return http.build(); } @Bean public RestClient restClient(RestClient.Builder builder) { return builder.build(); } @Bean(destroyMethod = "close") public RevocationCache revocationCache( @Value("${REDIS_HOST:redis}") String host, @Value("${REDIS_PORT:6379}") int port, @Value("${REDIS_CHANNEL:kc-events}") String channel ) { RevocationCache c = new RevocationCache(host, port, channel); c.start(); return c; } }