You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security Reactive OAuth2 Client:自定义刷新端点方案咨询

解决Spring OAuth2客户端适配分离式刷新端点的问题

问题背景

我在通过OAuth2授权码流访问受保护资源时遇到以下问题:对接的授权服务器会在初始访问令牌请求中返回刷新令牌,但该服务器的刷新端点与令牌端点相互独立。当前Spring客户端配置如下:

spring.security.oauth2.client.provider.test.authorization-uri=http://localhost:8085/oauth/authorize
spring.security.oauth2.client.provider.test.token-uri=http://localhost:8085/oauth/token

根据OAuth2 RFC标准,这种分离端点的设计并不合规,因此Spring Security未提供refresh-uri配置项。但我无法修改授权服务器的实现,只能在客户端侧调整刷新令牌请求的目标URI。

已尝试的方案

  • 查阅Spring Security文档,发现自定义刷新令牌请求仅支持修改请求参数和请求头,无法直接替换请求URI;
  • 尝试自定义WebClient,但最终请求仍会使用客户端提供者配置中的token-uri(参考AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java源码);
  • 考虑过在请求流程中修改OAuth2RefreshTokenGrantRequest来覆盖配置的令牌URI,但觉得这种方式不够简便,希望找到更优解。

依赖版本

  • spring-boot-starter-webflux:3.2.4
  • spring-boot-starter-security:3.2.4
  • spring-security-oauth2-client:6.2.3

可行解决方案

方案一:自定义刷新令牌响应客户端

通过继承WebClientReactiveOAuth2RefreshTokenTokenResponseClient并重写getTokenResponse方法,直接替换刷新请求的目标URI:

import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
import org.springframework.security.oauth2.client.endpoint.WebClientReactiveOAuth2RefreshTokenTokenResponseClient;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import reactor.core.publisher.Mono;

public class CustomRefreshTokenResponseClient extends WebClientReactiveOAuth2RefreshTokenTokenResponseClient {
    // 替换为授权服务器实际的刷新端点
    private static final String CUSTOM_REFRESH_URI = "http://localhost:8085/oauth/refresh";

    @Override
    public Mono<OAuth2AccessTokenResponse> getTokenResponse(OAuth2RefreshTokenGrantRequest grantRequest) {
        return getWebClient()
                .post()
                .uri(CUSTOM_REFRESH_URI)
                .headers(headers -> headers.setAll(grantRequest.getClientRegistration().getClientAuthenticationMethod().getHeaders(
                        grantRequest.getClientRegistration().getClientId(),
                        grantRequest.getClientRegistration().getClientSecret())))
                .bodyValue(createRequestBody(grantRequest))
                .retrieve()
                .bodyToMono(OAuth2AccessTokenResponse.class);
    }
}

然后在配置类中注册这个自定义客户端:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;

@Configuration
public class OAuth2ClientConfig {
    @Bean
    public ReactiveOAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> customRefreshTokenResponseClient() {
        return new CustomRefreshTokenResponseClient();
    }
}

方案二:通过WebClient过滤器替换URI

更简洁的方式是在WebClient的过滤器中拦截刷新令牌请求,替换目标URI:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.endpoint.WebClientReactiveOAuth2RefreshTokenTokenResponseClient;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import reactor.core.publisher.Mono;

@Configuration
public class OAuth2ClientConfig {
    private static final String CUSTOM_REFRESH_URI = "http://localhost:8085/oauth/refresh";

    @Bean
    public WebClientReactiveOAuth2RefreshTokenTokenResponseClient refreshTokenResponseClient() {
        WebClientReactiveOAuth2RefreshTokenTokenResponseClient client = new WebClientReactiveOAuth2RefreshTokenTokenResponseClient();
        client.setWebClient(client.getWebClient().mutate()
                .filter(ExchangeFilterFunction.ofRequestProcessor(request -> {
                    // 仅拦截原令牌端点的请求,替换为刷新端点
                    if (request.url().getPath().equals("/oauth/token")) {
                        return Mono.just(request.mutate().uri(CUSTOM_REFRESH_URI).build());
                    }
                    return Mono.just(request);
                }))
                .build());
        return client;
    }
}

内容的提问来源于stack exchange,提问作者Brian McDonnell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 01:06:07