我需要获取身份验证令牌并将其设置在标题中

时间:2018-10-02 19:02:38

标签: spring-boot spring-webflux

我是Spring引导和反应式编程的新手。

我将spring webflux webclient用于外部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; }
}

在应用程序启动期间,我将获取访问令牌并在webclient构建器中进行设置。我创建了一个过滤器来处理令牌到期后的身份验证失败。但是上面的代码引发错误,因为我使用了不应该在反应堆线程中使用的block()。我还能怎么处理呢?我正在使用oauth2资源所有者密码授予流程。还有其他方法可以处理流程吗?

2 个答案:

答案 0 :(得分:2)

您好,我遇到了同样的问题(Adding a retry all requests of WebClient),看起来您已经重复使用了。 但是这里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(); }

f(n)
  k=1
  for i=1 to n
    k=k+2 
    for j=1 to k             
      print(j)

答案 1 :(得分:0)

我知道这是一个旧线程,但我找不到初始问题的任何其他工作示例

基本上,我无法从上述示例中编写工作代码... 主要任务:使用 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; }
    }

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