我需要获取授权令牌并将其设置在 header

I need to fetch the auth token and set it in the header

我是 Spring 启动和响应式编程的新手。

我正在使用 spring webflux webclient 作为外部 api 服务。我需要获取授权令牌并将其设置在 header

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 资源所有者密码授予流程。有没有其他办法处理流量?

您好,我遇到了同样的问题 (Adding a retry all requests of 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();
    }

我知道这是一个旧话题,但我找不到任何其他适用于初始问题的示例

基本上,我无法根据上述示例编写工作代码... 主要任务:使用 WebClient 实例通过提供 Bearer 令牌来获取受保护的资源。 Bearer 令牌可以通过单独的请求来请求。

Mono authenticate() 应该可以正常获取新令牌。

        WebClient client2 =  WebClient.builder()
                                    .baseUrl(SERVER_URL)
                                    .filter((request, next) -> {
                                        return next.exchange(request)
                                                .flatMap( 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 " + token.getAccessToken())
                                    .build();

因为上面的例子无法用 flatMap() 替换“.block()”

和第二个例子

        WebClient client3 =  WebClient.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();

不确定什么是“tokenProvider.getAccessToken()”和“.flatMap(Token::getAccessToken)”不会接受 由于

    class Token {
        String token = "";
        
        public String getAccessToken() { return token; }
    }

抱歉,我是新手。如果您有工作示例,请在此线程中分享