我是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资源所有者密码授予流程。还有其他方法可以处理流程吗?
答案 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; }
}
抱歉,我是新手。如果您有一个工作示例,请在此线程中分享