spring-boot - 我需要获取身份验证令牌并将其设置在标题中
问题描述
我是 Spring Boot 和响应式编程的新手。
我正在将 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 builder 中。我创建了一个过滤器来处理令牌到期后的身份验证失败。但是上面的代码会抛出错误,因为我使用了不应该在反应器线程中使用的 block()。我还能怎么处理?我正在使用 oauth2 资源所有者密码授予流程。有没有其他方法来处理流量?
解决方案
嗨,我有同样的问题(添加重试 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();
}
推荐阅读
- firebase - Firebase 云函数部署错误TS2614
- python - 如何强制 matplotlib 热图单元格为矩形?
- python - 将多个图像转换为 pdf
- gitlab - 如何向 Gitlab 花费时间跟踪项目添加注释
- javascript - 将 style[hash].css 拆分为动态加载的块
- java - phpexcel切换到嵌入式单元格图片?
- html - Webflow中视频容器中的黑线
- android - 单击更改可见性以隐藏一个 ImageView 并延迟出现其他 ImageView 以生成动画 android 小部件
- html - 响应式 div:具有相同高度的并排 div
- adblock - 如何在 Adblock plus 元素过滤器中选择 url 的路径?