Spring Security 5.1 - Получить токен для потока учетных данных клиента с помощью WebClient - PullRequest
0 голосов
/ 07 ноября 2018

Я пытаюсь получить токен на предъявителя через webclient со следующей настройкой для интеграционного теста защищенного сервера ресурсов в приложении сервлета.

spring:
  security:
    oauth2:
      client:
        registration:
          idp:
            clientId: id
            clientSecret: secret
            authorization-grant-type: client_credentials
            scope: read
        provider:
          idp:
            authorization-uri: myidp/authorization.oauth2
            token-uri: myidp/token.oauth2
            user-info-uri: myidp/userinfo.openid
            user-name-attribute: name

и фасоль

    @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
        // oauth.setDefaultOAuth2AuthorizedClient(true);
        // (optional) set a default ClientRegistration.registrationId
        // oauth.setDefaultClientRegistrationId("client-registration-id");
        return WebClient.builder().apply(oauth.oauth2Configuration()).build();
    }

и автоматическое подключение веб-клиента к тесту и вызов его так:

webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("idp")).retrieve()
                .bodyToMono(String.class).block();

Я предполагаю, что функция exchange либо получит токен доступа, если он доступен, либо сделает вызов для получения нового от IDP. Однако он всегда будет неудачным, так как HttpSessionOAuth2AuthorizedClientRepository, так как HttpServletRequest равен нулю.

С учетом того, что общий тест выглядит следующим образом, он автоматически настраивается для настройки некоторых bean-компонентов для поставщика IDP.

@SpringBootTest(classes = WebITApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
@ActiveProfiles("web-it")
class WebJwtIt {

    @LocalServerPort
    private int port;

    @Autowired
    private WebClient webClient;

    @Test
    void testIdpJwt() {

        String response = webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("ping")).retrieve()
                .bodyToMono(String.class).block();
        assertThat(response).isEqualTo("pass");
    }

    @RestController
    @SpringBootApplication
    @ImportAutoConfiguration(IdpAutoConfiguration.class)
    static class WebITApplication implements IdpSecurityAdapter {

              @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
        // oauth.setDefaultOAuth2AuthorizedClient(true);
        // (optional) set a default ClientRegistration.registrationId
        // oauth.setDefaultClientRegistrationId("client-registration-id");
        return WebClient.builder().apply(oauth.oauth2Configuration()).build();
    }
        public static void main(String args[]) {

            new SpringApplicationBuilder().profiles("web-it").build().run(WebITApplication.class, args);
        }

        @GetMapping
        public String secured() {
            return "secured";
        }

        @GetMapping("/web/it")
        public String securedOne() {
            return "pass";
        }

        @Override
        public void configure(final HttpSecurity httpSecurity) throws IdpSecurityAdapterException {
            try {
                httpSecurity.oauth2Client();
            } catch (Exception e) {
                throw new IdpSecurityAdapterException("Failed to Configure Oauth2Client", e);
            }
        }

        @Override
        public IdpProvider getIdpProvider() {
            return IdpProvider.MyIdp;
        }
    }

Есть ли у веб-клиента возможность получить для меня токен и добавить его в запрос? Я знаю, что это было возможно с spring-security-oauth:OAuthRestTemplate и, читая документацию, я думал, что это возможно с помощью веб-клиента.

1 Ответ

0 голосов
/ 02 декабря 2018

Проблема здесь в том, что вы неправильно копируете свой WebClient.

Поскольку вы находитесь на стороне клиента , у вас нет доступа к OAuth2AuthorizedClientRepository. Предполагается, что этот bean-компонент связан с сервером ресурсов, в который вы входите, используя объявление метода .oauth2Login() в конфигурации HttpSecurity. Эти детали объясняются здесь: Spring Security 5 Oauth2 Login .

Опять же, вы находитесь на клиентской стороне , поэтому вам нужна функция фильтра обмена, которая будет инициировать запрос к серверу авторизации для получения токена JWT. Вместо этого вы можете использовать ServerOAuth2AuthorizedClientExchangeFilterFunction.

Вам лучше использовать WebClientCustomizer, чтобы добавить функцию фильтра обмена в фильтр WebClient. Зачем ? Просто потому, что введение в ваше приложение Spring WebClient.Builder позволит вам получить доступ к собственным метрикам, связанным с веб-биржами.

Следовательно, вы создадите свой WebClient, используя новый экземпляр компонента UnAuthenticatedServerOAuth2AuthorizedClientRepository, подобный следующему:

// Use injection to get an in-memory reposiroty or client registrations
@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrations) {

    // Provides support for an unauthenticated user such as an application
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());

    // Build up a new WebClientCustomizer implementation to inject the oauth filter
    // function into the WebClient.Builder instance
    return new WebClientSecurityCustomizer(oauth);
}

Поскольку вы находитесь на клиентской стороне , вы не ассоциируете пользователя с вашим процессом, поэтому вы не можете использовать никакие авторизованные экземпляры bean-репозитория клиента. Проверьте документацию Spring Security: Документация Spring Security: класс UnAuthenticatedServerOAuth2AuthorizedClientRepository .

Я попытался подвести итог демонстрационного примера в следующем проекте GitHub: GitHub - сценарий Spring-OAuth2 Machine-to-Machine .

Надеюсь, это поможет вам лучше понять конфигурацию WebClient. Пожалуйста, спросите, если у вас есть какие-либо вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...