Мне нужно получить токен авторизации и установить его в шапке - PullRequest
0 голосов
/ 02 октября 2018

Я новичок в загрузочном и реактивном программировании Spring.

Я использую веб-клиент Spring Webflux для внешнего API-сервиса.Мне нужно получить токен авторизации и установить его в заголовке

WebClient.builder()
            .baseUrl(baseUrl)
            .filter((request, next) -> {
                return next.exchange(request)
                        .flatMap((Function<ClientResponse, Mono<ClientResponse>>) clientResponse -> {
                            if (clientResponse.statusCode().value() == 401) {
                                return authenticate().map(token -> {
                                    Token accessToken = authenticate().block();
                                    ClientRequest retryRequest = ClientRequest.from(request).header("Authorisation", "Bearer " + accessToken.getAccessToken()).build();
                                    return next.exchange(retryRequest);
                                }).
                            } else {
                                return Mono.just(clientResponse);
                            }
                        });
            })
            .defaultHeader("Authorization", "Bearer " + authToken.getAccessToken())
            .build();


private Mono<Token> authenticate() {
    MultiValueMap<String, String> params = new LinkedMultiValueMap();
    params.add("client_id", clientId);
    params.add("client_secret", clientSecret);
    params.add("grant_type", "password");
    params.add("username", username);
    params.add("password", password);

    WebClient client = WebClient.create(baseUrl);
    return client
            .post()
            .uri(tokenUri)
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .syncBody(params)
            .retrieve()
            .bodyToMono(Token.class);
}

private static class Token {
    @JsonProperty("access_token")
    private String accessToken;

    public String getAccessToken() { return accessToken; }
}

. Во время запуска приложения я получу токен доступа и установлю его в построителе веб-клиента.Я создал фильтр для обработки ошибок аутентификации после истечения срока действия токена.Но приведенный выше код выдает ошибку, потому что я использовал block (), который не должен использоваться в потоке реактора.Как еще я могу справиться с этим?Я использую поток предоставления пароля владельца ресурса oauth2.Есть ли другой способ справиться с потоком?

1 Ответ

0 голосов
/ 03 октября 2018

Привет У меня возникла та же проблема ( Добавление повторных попыток для всех запросов WebClient ), которая выглядит так, как будто вы повторно использовали.но здесь flatmap ваш друг, если у вас есть Mono<Mono<T>>, вы можете сгладить его с помощью flatMap

builder.baseUrl("http://localhost:8080")
             //sets the header before the exchange
            .filter(((request, next) -> tokenProvider.getAccessToken()
                                .map(setBearerTokenInHeader(request))
                                .flatMap(next::exchange)))
            //do the exchange
            .filter((request, next) -> next.exchange(request)
                    .flatMap(clientResponse -> {
                        if (clientResponse.statusCode().value() == 401) {
                          //If unauthenicated try again 
                            return authenticate()
                                    .flatMap(Token::getAccessToken)
                                    .map(setBearerTokenInHeader(request))
                                    .flatMap(next::exchange);
                        } else {
                            return Mono.just(clientResponse);
                        }
                    }))
            .build();

private Function<String, ClientRequest> setBearerTokenInHeader(ClientRequest request) {
        return token -> ClientRequest.from(request).header("Bearer ", token).build();
    }
...