如何在 Spring Webflux WebClient 中处理令牌刷新

How to handle token refreshing in Spring Webflux WebClient

我想创建一些用于 WebClient 的身份验证服务,因此它会在需要时自动刷新令牌:

@Service
public class AuthService {

    private String token;

    private final WebClient webClient;

    private final Map<String, String> bodyValues;

    @Autowired
    public AuthService(WebClient webClient) {
        this.webClient = webClient;
        this.bodyValues = new HashMap<>();
        this.bodyValues.put("user", "myUser");
        this.bodyValues.put("password", "somePassword");
    }

    public String getToken() {
        if (this.token == null || this.isExpired(this.token) {
            this.refreshToken();
        } 
        return this.token;
    }


    private void refreshToken() {
        this.token = webClient.post()
                .uri("authEndpointPath")
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(bodyValues))
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    private boolean isExpired() {
        //implementation
    }
}

它在过期时正确获取令牌。有没有办法使用它 ONLY ONCE,而不将其注入其他服务?我正在考虑定义使用 authService.getToken() 方法的 Bean

@Configuration
public class CustomWebClientConfig {

    private final AuthService authService;

    @Autowired
    public CustomWebClientConfig(AuthService authService) {
        this.authService = authService;
    }  
  
    @Bean("myCustomWebClient")
    WebClient webClient() {
        return WebClient.builder()
                .defaultHeader("Access-Token", authService.getToken())
                .build()
    }
}

但显然它只会在应用程序启动时获得一次令牌。有没有办法以某种方式注入它或拦截所有 webclient 请求然后添加令牌?

您可以声明一个自定义 WebClientfilter 应用于每个请求。

@Configuration
public class CustomWebClientConfig {

    private final AuthService authService;

    @Autowired
    public CustomWebClientConfig(AuthService authService) {
        this.authService = authService;
    }  
  
    @Bean("myCustomWebClient")
    WebClient webClient() {
        return WebClient.builder()
                .filter(ExchangeFilterFunction.ofRequestProcessor(
                    (ClientRequest request) -> Mono.just(
                        ClientRequest.from(request)
                            .header("Access-Token", authService.getToken())
                            .build()
                    )
                ))
                .build();
    }
}