java - 如何防止通过 WebClient 进行多次身份验证调用
问题描述
以下代码将获取 20 台设备,并将使用来自在线服务的一些数据。
为了使用在线服务,WebClient 需要获取访问令牌(authorization-grant-type=client_credentials)
spring.security.oauth2.client.registration.web.client-id=xxxx
spring.security.oauth2.client.registration.web.client-secret=xxxx
spring.security.oauth2.client.registration.web.scope=xxxx
spring.security.oauth2.client.registration.web.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.web.token-uri=https://xxxx
配置:
@Configuration
public class Config {
@Autowired
public ClientRegistrationRepository clientRegistrationRepository;
@Bean
public WebClient webClient(ExchangeFilterFunction getOAuth2FilterFunction) {
logger.info("** start webClient **");
return WebClient.builder().filter(getOAuth2FilterFunction).build();
}
@Bean
public ExchangeFilterFunction getOAuth2FilterFunction(ReactiveClientRegistrationRepository clientRegistrationRepository) {
logger.info("** start getOAuth2FilterFunction **");
InMemoryReactiveOAuth2AuthorizedClientService authorizedClientService = new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(new ClientCredentialsReactiveOAuth2AuthorizedClientProvider());
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2FilterFunction = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2FilterFunction.setDefaultClientRegistrationId("web");
return oauth2FilterFunction;
}
@Bean
public ReactiveClientRegistrationRepository clientRegistrations() {
logger.info("** start clientRegistrations **");
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId("web");
return new InMemoryReactiveClientRegistrationRepository(clientRegistration);
}
网络客户端:
private void getData(List<Device> initlist) {
logger.info("** start getDeviceData **");
List<Mono<DeviceDto>> jsonDeviceList = initlist.stream()
.map(device -> webClient.post().uri(infoUri)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.body(Mono.just(device.getMacAddress()),String.class)
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("web"))
.retrieve()
.bodyToMono(DeviceDto.class))
.collect(Collectors.toList());
ObjectMapper mapper = new ObjectMapper();
Flux<DeviceDto> mergedMonos = Flux.fromIterable(jsonDeviceList).flatMapSequential(Function.identity());
mergedMonos.map(device -> mapper.valueToTree(device)).collectList().subscribe(list -> {
generateCsv(list);
});
}
问题是对于每个服务请求,都会有来自身份验证服务器的等效访问令牌请求。因此,对于列表中的所有 20 台设备,WebClient 将请求访问令牌 20 次。
如何将其更改为只有一个电话而不是 20 ?
谢谢
解决方案
@Toerktumlare 说的是对的。如果你想调用一次oauth服务器,你只需要在第一次请求时将access_token缓存在内存或redis中,然后在过期之前使用相同的access_token。
WebClient webClient = WebClient.builder()
.defaultHeader("Authorization", "Bearer " + getAccessToken())
.build();
private String getAccessToken() {
// get access_token from redis
// if expiring, it will return null
String access_token = (String) redisTemplate.opsForValue().get("access_token");
if (null != access_token) {
return access_token;
}
// get access_token from oauth server again and cache it into redis
return getAccessTokenFromOauthServer();
}
推荐阅读
- python - Python DataFrame:根据条件删除重复项?
- c++ - 使用 MATLAB 编码器对唯一函数进行 C++ 转换
- html - 我无法在 Angular 应用程序的打印对话框中更改布局
- yaml - 从可选的 YAML 文件中读取空手道配置 - 是否检查文件是否存在?
- rust - Rc Refcell 的变异字段取决于其其他内部字段
- r - 将图片作为单元格的内容时,kableExtra 不起作用
- python - pygame 中的增长函数 - SnakeGame
- python - 如何在 Matplotlib 饼图周围绘制箭头以将每个标签指向圆圈中的相应部分?
- r - rasterVis levelplot 图例绘图错误
- linux - 验证在同一物理机上运行的另一个进程的身份