Java 如何防止通过WebClient进行多次身份验证呼叫
下面的代码将获取20个设备,并使用来自在线服务的一些数据 为了使用在线服务,WebClient需要获取访问令牌(授权授予类型=客户端凭据) 配置:Java 如何防止通过WebClient进行多次身份验证呼叫,java,spring-security,spring-webflux,spring-security-oauth2,Java,Spring Security,Spring Webflux,Spring Security Oauth2,下面的代码将获取20个设备,并使用来自在线服务的一些数据 为了使用在线服务,WebClient需要获取访问令牌(授权授予类型=客户端凭据) 配置: @Configuration public class Config { @Autowired public ClientRegistrationRepository clientRegistrationRepository; @Bean public WebClient webClient(ExchangeFilterFunction getO
@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);
});
}
网络客户端:
@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);
});
}
private void getData(List initlist){
logger.info(“**启动getDeviceData**”);
List jsonDeviceList=initlist.stream()
.map(设备->webClient.post().uri(infoUri)
.header(HttpHeaders.CONTENT\u TYPE、MediaType.APPLICATION\u JSON\u值)
.header(HttpHeaders.ACCEPT,MediaType.APPLICATION\u JSON\u值)
.body(Mono.just(device.getMacAddress()),String.class)
.attributes(ServerOAuth2AuthorizedClientChangeFilterFunction.clientRegistrationId(“web”))
.retrieve()
.BodyToNo(设备到类))
.collect(Collectors.toList());
ObjectMapper mapper=新的ObjectMapper();
Flux mergedMonos=Flux.fromIterable(jsonDeviceList).flatMapSequential(Function.identity());
mergedMonos.map(设备->映射器.valueToTree(设备)).collectList().subscribe(列表->{
生成ECSV(列表);
});
}
问题在于,对于每个服务请求,都会有来自身份验证服务器的等效访问令牌请求。因此,对于列表中的所有20台设备,WebClient将请求访问令牌20次
如何将此更改为只有一个电话而不是20个
谢谢你,@Toerktumlare说的是对的。如果要调用oauth服务器一次,只需在第一次请求时将access_令牌缓存在内存或redis中,然后在其过期之前使用相同的access_令牌
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();
}
您尝试了什么?我可以通过调试模式看到有20个身份验证调用,这不是我的问题,我的问题是,您编写了什么代码来尝试解决这个问题。无论您在帖子中看到什么,您都编写了一个拦截过滤器,它将拦截每个请求,并调用oauth服务器。ofc it将为每个用户执行一个请求。如果你不想,那么先做一个请求,然后再做你的20个请求。。。。使用常规网络客户端。如何获取令牌?从oauth服务器获取令牌。谢谢Holinc,是的,从服务器获取令牌并通过网络客户端发送成功的令牌请求的过程运行良好。但是我如何打印代币呢?我需要令牌,以便通过另一个函数将其添加到请求中。