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

Spring Security:oauth2Login与oauth2Client选型及AccessToken获取方案

解决方案:利用Spring Security开箱即用实现用户授权后的API调用

你的需求完全可以通过Spring Security的OAuth2支持开箱即用实现,无需大量自定义开发。核心是获取存储在OAuth2AuthorizedClient中的access_token,Spring Security在oauth2Login流程中已经自动帮你完成了token的获取与存储,只是默认未暴露在Authentication的属性中。

一、核心思路

oauth2Login已经完成了用户认证、授权码交换token的流程,获取到的access_token和refresh_token会被Spring Security保存在OAuth2AuthorizedClient对象中,你可以通过以下两种方式轻松获取:

方式1:使用@RegisteredOAuth2AuthorizedClient注解直接注入

在控制器方法或服务方法中,通过该注解直接获取指定客户端的授权对象,从中提取access_token:

@Controller
public class MyController {
    
    private final ReportService reportService;
    
    public MyController(final ReportService reportService) {
        this.reportService = reportService;
    }
    
    @GetMapping({"", "/"})
    public String index(final Model model,
                        // 注入对应客户端的授权对象
                        @RegisteredOAuth2AuthorizedClient("the-provider") OAuth2AuthorizedClient authorizedClient) {
        String accessToken = authorizedClient.getAccessToken().getTokenValue();
        model.addAttribute("report", reportService.generateReport(accessToken));
        return "index";
    }
}

方式2:通过OAuth2AuthorizedClientService主动查询

如果需要在服务类中获取token,可以注入OAuth2AuthorizedClientService,根据当前认证用户的信息加载授权对象:

@Service
public class ReportService {
    private final OAuth2AuthorizedClientService authorizedClientService;
    private final RestTemplate restTemplate;

    public ReportService(OAuth2AuthorizedClientService authorizedClientService, RestTemplate restTemplate) {
        this.authorizedClientService = authorizedClientService;
        this.restTemplate = restTemplate;
    }

    public String generateReport() {
        // 获取当前登录用户的认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // 加载对应客户端的授权对象
        OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient(
                "the-provider", authentication.getName());
        String accessToken = authorizedClient.getAccessToken().getTokenValue();

        // 携带access_token调用第三方API
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(accessToken);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        ResponseEntity<String> response = restTemplate.exchange(
                "https://provider.domain.com/api/reports",
                HttpMethod.GET,
                entity,
                String.class);
        return response.getBody();
    }
}

二、进阶:自动携带token的WebClient配置

如果想更优雅地调用API,无需手动处理token,可以配置带有OAuth2拦截器的WebClient,它会自动为请求带上当前用户的access_token,并在token过期时自动刷新:

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Filter =
                new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        return WebClient.builder()
                .apply(oauth2Filter.oauth2Configuration())
                .build();
    }

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientService authorizedClientService) {
        // 构建支持授权码和刷新token的客户端提供者
        OAuth2AuthorizedClientProvider provider = OAuth2AuthorizedClientProviderBuilder.builder()
                .authorizationCode()
                .refreshToken()
                .build();
        DefaultOAuth2AuthorizedClientManager manager = new DefaultOAuth2AuthorizedClientManager(
                clientRegistrationRepository, authorizedClientService);
        manager.setAuthorizedClientProvider(provider);
        return manager;
    }
}

之后在ReportService中直接使用WebClient调用API即可,无需手动处理token:

@Service
public class ReportService {
    private final WebClient webClient;

    public ReportService(WebClient webClient) {
        this.webClient = webClient;
    }

    public String generateReport() {
        return webClient.get()
                .uri("https://provider.domain.com/api/reports")
                // 指定使用的客户端ID
                .attributes(oauth2AuthorizedClient("the-provider"))
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }
}

三、关于oauth2Client的说明

你无需切换到oauth2Client,因为oauth2Login已经包含了用户登录场景下的授权码流程支持,oauth2Client更多用于客户端凭证模式、客户端侧的授权码流程等非用户登录场景。你的需求是用户登录后代表用户调用API,oauth2Login的配置已经完全满足。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:44:53