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

如何在Spring Boot+Spring Security OAuth2中提取Refresh Token值?

如何在Spring Boot客户端中简便拦截Refresh Token

嘿,针对你使用Spring Boot 2.x、Spring Security 5.x + OAuth2 2.3.x对接第三方资源服务器的场景,我有几个轻量方案可以帮你快速拦截到Refresh Token的值,不用立刻搭建完整的Refresh Token Repository:

方案1:自定义OAuth2AccessTokenResponseClient(最直接推荐)

这个方案是在获取Token的核心环节直接拦截响应,因为OAuth2AccessTokenResponseClient负责和授权服务器交互并返回Token响应,我们可以重写它的方法来提取Refresh Token:

import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;

@Component
public class CustomTokenResponseClient extends DefaultAuthorizationCodeTokenResponseClient {

    @Override
    public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
        // 先调用父类获取完整的Token响应
        OAuth2AccessTokenResponse tokenResponse = super.getTokenResponse(authorizationCodeGrantRequest);
        
        // 提取Refresh Token
        String refreshToken = tokenResponse.getRefreshToken().getTokenValue();
        
        // 这里可以做你需要的操作:比如临时存入内存、打印日志、或者预存到后续要做的Repository里
        System.out.println("拦截到Refresh Token:" + refreshToken);
        
        return tokenResponse;
    }
}

然后在你的Security配置里,把这个自定义的Client注入到OAuth2登录流程中:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomTokenResponseClient customTokenResponseClient;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login()
                .tokenEndpoint()
                    .accessTokenResponseClient(customTokenResponseClient);
    }
}

这个方案的优势是:在Token获取的第一时间拿到Refresh Token,不会错过任何场景(比如首次登录、Token自动刷新),完全贴合Spring Security OAuth2的原生流程,后续迁移到正式Repository也很顺畅。

方案2:利用AuthenticationSuccessHandler拦截认证成功事件

当用户通过OAuth2认证成功后,AuthenticationSuccessHandler会被触发,我们可以从认证对象中提取已授权的客户端信息,进而拿到Refresh Token:

import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CustomAuthSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private OAuth2AuthorizedClientService authorizedClientService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        if (authentication instanceof OAuth2AuthenticationToken) {
            OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
            // 获取已授权的客户端
            OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient(
                    oauthToken.getAuthorizedClientRegistrationId(),
                    oauthToken.getName()
            );
            
            // 提取Refresh Token
            if (authorizedClient.getRefreshToken() != null) {
                String refreshToken = authorizedClient.getRefreshToken().getTokenValue();
                System.out.println("认证成功,拦截到Refresh Token:" + refreshToken);
            }
        }
        
        // 继续执行默认的成功跳转逻辑
        response.sendRedirect("/home");
    }
}

然后在Security配置中配置这个SuccessHandler:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthSuccessHandler customAuthSuccessHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login()
                .successHandler(customAuthSuccessHandler);
    }
}

这个方案适合只需要在用户首次登录时获取Refresh Token的场景,不过如果是后台自动刷新Token的情况(比如用OAuth2AuthorizedClientManager自动刷新),这个Handler不会被触发,所以推荐结合方案1使用。

方案3:自定义Filter拦截Token响应(备选)

如果上面两种方案都不适合,你可以通过自定义Filter来拦截授权服务器返回的Token响应,解析响应体中的Refresh Token:

import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TokenResponseFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 只拦截Token端点的响应(根据你的授权服务器Token地址调整)
        if (request.getRequestURI().contains("/oauth2/token")) {
            // 包装响应以读取响应体
            ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
            
            filterChain.doFilter(request, wrappedResponse);
            
            // 读取响应体内容并解析Refresh Token
            String responseBody = new String(wrappedResponse.getContentAsByteArray(), wrappedResponse.getCharacterEncoding());
            if (responseBody.contains("refresh_token")) {
                // 这里可以用Jackson/Gson做正规JSON解析,示例用简单字符串处理
                String refreshToken = responseBody.split("\"refresh_token\":\"")[1].split("\"")[0];
                System.out.println("Filter拦截到Refresh Token:" + refreshToken);
            }
            
            // 必须把缓存的内容写回原始响应
            wrappedResponse.copyBodyToResponse();
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

然后在Security配置中注册这个Filter:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterAfter(new TokenResponseFilter(), OAuth2AuthorizationCodeGrantFilter.class);
    }
}

这个方案比较灵活,但需要自己处理响应体的解析,而且要注意授权服务器的Token响应格式,适合特殊场景下使用。


内容的提问来源于stack exchange,提问作者Trynkiewicz Mariusz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:32:39