Несколько дней назад была поставлена задача сделать запросы между сервисами с токеном. У нас используется Keycloak в качестве SSO. В силу того, что нужно всё на базовом уровне (ничего специфического),то имеет смысл использовать Feign Client (OpenFeign) для Spring Boot.
Начал копаться в вопросе включения OAuth для Feign и через 1-2 дня наткнулся на только что опубликованную статью от @Kinski, но, как и везде, в ней и в других статьях есть некоторые неточности и даже в той же документации. Опишу различные варианты включения, которые я счёл верными и простыми с некоторым описанием.
В нашем случае client.registration у нас keycloak.
Spring Boot 2.7.6
Spring Cloud 2021.0.5
1. Включаем OAuth2 для всех Feign клиентов
Первая неточность по документации - это параметры включения как раз этого OAuth для Feign. Вместо настроек для Spring
spring:
cloud:
openfeign:
oauth2:
enabled: true
clientRegistrationId: keycloak
которые ничего не включат.
надо использовать
feign:
oauth2:
enabled: true
clientRegistrationId: keycloak
естественно подключаем пакеты:
- spring-boot-starter-security
- spring-boot-starter-oauth2-client
- spring-cloud-starter-openfeign.
Далее включаем сам OAuth2Client security
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ваши настройки +
.oauth2Client();
return http.build();
}
ну и прописываем настройки для OAuth2 клиента
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: id вашего клиента для провайдера
client-secret: ваш секрет
authorization-grant-type: client_credentials
provider: keycloak
provider:
keycloak:
token-uri: адрес до провайдера токена
После этого все запросы через Feign Client будут обогощаться OAuth токеном.
2. Включаем OAuth2 только для нужных Feign клиентов
Повторяем из 1го раздела пункты 3 и 4. Далее создаём конфигурацию для Feign
public class OAuthFeignConfig {
private final OAuth2ClientProperties oAuth2ClientProperties;
public OAuthFeignConfig(OAuth2ClientProperties oAuth2ClientProperties) {
this.oAuth2ClientProperties = oAuth2ClientProperties;
}
@Bean
@ConditionalOnBean({OAuth2AuthorizedClientService.class, ClientRegistrationRepository.class})
@ConditionalOnMissingBean
public OAuth2AuthorizedClientManager feignOAuth2AuthorizedClientManager(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService oAuth2AuthorizedClientService) {
return new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, oAuth2AuthorizedClientService);
}
@Bean
@ConditionalOnBean(OAuth2AuthorizedClientManager.class)
public OAuth2AccessTokenInterceptor defaultOAuth2AccessTokenInterceptor(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
return new OAuth2AccessTokenInterceptor(oAuth2ClientProperties.getRegistration().keySet().iterator().next(), oAuth2AuthorizedClientManager);
}
}
Фактически код создания бинов скопирован из исходников и поправлен только в моменте прописывания имени клиентской регистрации из настроек.
В раскопках помогли исходники:
FeignAutoConfiguration
fromorg.springframework.cloud.openfeign
OAuth2AccessTokenInterceptor
fromorg.springframework.cloud.openfeign.security
В 19й строке использовал oAuth2ClientProperties.getRegistration().keySet().iterator().next()
для получения первой в списке регистрации (чтобы не хардкодить. У нас это keycloak).
теперь в любом нашем FeignClient дописываем конфигурацию:
@FeignClient(value = "client-name", url = "your_url", configuration = OAuthFeignConfig.class)
PS: статья первая,сильно не бейте. Решил оформить после статьи от @Kinskiс более детальным описанием и раскрытием нюансов, которые на просторах интернета не описаны нигде.
Если кому-то статья сократит время разработки и поможет - буду рад!