Несколько дней назад была поставлена задача сделать запросы между сервисами с токеном. У нас используется 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

которые ничего не включат.

  1. надо использовать

feign:
  oauth2:
    enabled: true
    clientRegistrationId: keycloak

естественно подключаем пакеты:
- spring-boot-starter-security
- spring-boot-starter-oauth2-client
- spring-cloud-starter-openfeign.

  1. Далее включаем сам OAuth2Client security

public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        // ваши настройки +
        .oauth2Client();
    return http.build();
}
  1. ну и прописываем настройки для 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 from org.springframework.cloud.openfeign

  • OAuth2AccessTokenInterceptor from org.springframework.cloud.openfeign.security

В 19й строке использовал oAuth2ClientProperties.getRegistration().keySet().iterator().next() для получения первой в списке регистрации (чтобы не хардкодить. У нас это keycloak).
теперь в любом нашем FeignClient дописываем конфигурацию:

@FeignClient(value = "client-name", url = "your_url", configuration = OAuthFeignConfig.class)

PS: статья первая,сильно не бейте. Решил оформить после статьи от @Kinskiс более детальным описанием и раскрытием нюансов, которые на просторах интернета не описаны нигде.
Если кому-то статья сократит время разработки и поможет - буду рад!

Комментарии (0)