Feign и Spring Security 5 - Учетные данные клиента - PullRequest
2 голосов
/ 06 августа 2020

Я пытаюсь вызвать какую-то бэкэнд-систему, которая защищена типом предоставления client_credentials из клиентского приложения Feign.

Токен доступа из бэкэнд-системы можно получить с помощью следующей структуры curl (точно так же, как example):

curl --location --request POST '[SERVER URL]/oauth/grant' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: WebSessionID=172.22.72.1.1558614080219404; b8d49fdc74b7190aacd4ac9b22e85db8=2f0e4c4dbf6d4269fd3349f61c151223' \
--data-raw 'grant_type=client_credentials' \
--data-raw 'client_id=[CLIENT_ID]' \
--data-raw 'client_secret=[CLIENT_SECRET]'

{"accessToken":"V29C90D1917528E9C29795EF52EC2462D091F9DC106FAFD829D0FA537B78147E20","tokenType":"Bearer","expiresSeconds":7200}

Затем этот accessToken должен быть установлен в заголовке для последующих бизнес-вызовов к бэкэнд-системе.

Итак, теперь мой вопрос: как реализовать это с помощью Feign и Spring Безопасность загрузки 5. После некоторого исследования я пришел к этому решению (которое не работает):

  1. Определите моего клиента в application.yml:
spring:
  security:
    oauth2:
      client:
        registration:
          backend:
            client-id:[CLIENT_ID]
            client-secret: [CLIENT_SECRET]
            authorization-grant-type: client_credentials
    
        provider:
          backend:
            token-uri: [SERVER URL]/oauth/grant
Создайте компонент OAuth2AuthorizedClientManager, чтобы иметь возможность авторизовать (или повторно авторизовать) клиента OAuth 2.0:
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientRepository authorizedClientRepository) {

    DefaultOAuth2AuthorizedClientManager authorizedClientManager =
            new DefaultOAuth2AuthorizedClientManager(
                    clientRegistrationRepository, authorizedClientRepository);

    return authorizedClientManager;
}
Создайте перехватчик запросов Feign, который использует OAuth2AuthorizedClientManager:
public class OAuthRequestInterceptor implements RequestInterceptor {

    private OAuth2AuthorizedClientManager manager;

    public OAuthRequestInterceptor(OAuth2AuthorizedClientManager manager) {
        this.manager = manager;
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        OAuth2AuthorizedClient client = this.manager.authorize(OAuth2AuthorizeRequest.withClientRegistrationId("backend").principal(createPrincipal()).build());
        String accessToken = client.getAccessToken().getTokenValue();
        requestTemplate.header(HttpHeaders.AUTHORIZATION, "Bearer" + accessToken);
    }

    private Authentication createPrincipal() {
        return new Authentication() {
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return Collections.emptySet();
            }

            @Override
            public Object getCredentials() {
                return null;
            }

            @Override
            public Object getDetails() {
                return null;
            }

            @Override
            public Object getPrincipal() {
                return this;
            }

            @Override
            public boolean isAuthenticated() {
                return false;
            }

            @Override
            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
            }

            @Override
            public String getName() {
                return "backend";
            }
        };
    }
}
Создайте FeignConfig, использующий перехватчик:
public class FeignClientConfig {


    @Bean
    public OAuthRequestInterceptor repositoryClientOAuth2Interceptor(OAuth2AuthorizedClientManager manager) {
        return new OAuthRequestInterceptor(manager);
    }
}
И это мой клиент Feign:
@FeignClient(name = "BackendRepository", configuration = FeignClientConfig.class, url = "${BACKEND_URL}")
public interface BackendRepository {

    @GetMapping(path = "/healthChecks", produces = MediaType.APPLICATION_JSON_VALUE)
    public Info healthCheck();
}

При запуске этого кода я получаю сообщение об ошибке:

org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse] and content type [text/html;charset=utf-8]

Отладка кода выглядит как DefaultClientCredentialsTokenResponseClient. запрос конечной точки аутентификации с использованием Basi c Authentication. Хотя я никогда это не настраивал.

Подскажите, что я могу сделать? Может быть, есть совсем другой подход к этому.

1 Ответ

0 голосов
/ 20 августа 2020

Я пробовал твой подход. К сожалению, безуспешно. Но этот сработал для меня: Spring Cloud Feign OAuth2 request interceptor не работает . Похоже, сейчас я использую много хищников, но, по крайней мере, это работает.

...