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

Spring Boot应用调用OAuth2 client_credentials授权API遇阻求指导

解决方案:Spring Boot调用Client Credentials模式的OAuth2保护API

核心问题分析

你的代码存在以下几个关键问题:

  • 手动加载OAuth2AuthorizedClient的方式错误,loadAuthorizedClient的第二个参数是用户主体ID,但Client Credentials模式下无需用户,应该让Spring自动管理token的获取与刷新。
  • RestTemplate未集成OAuth2自动token注入逻辑,手动拼接Header无法处理token过期等场景。
  • 旧的WebSecurityConfigurerAdapter配置未启用OAuth2客户端支持,且该类已被Spring Security弃用。

正确实现步骤

1. 确保依赖正确

确保pom.xml(或build.gradle)包含Spring OAuth2 Client starter:

<!-- Maven -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

2. 保留现有application.properties配置

你的配置是正确的,无需修改:

spring.application.name=oauth-test

spring.security.oauth2.client.registration.myuser.client-id=userId
spring.security.oauth2.client.registration.myuser.client-secret=userPassword
spring.security.oauth2.client.registration.myuser.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.myuser.scope=read
spring.security.oauth2.client.provider.myuser.token-uri=https://auth-server-app/v1/oauth/token

3. 配置带OAuth2支持的RestTemplate

创建配置类,让RestTemplate自动获取并携带OAuth2 token:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.support.OAuth2AuthorizedClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;

@Configuration
public class OAuth2RestTemplateConfig {

    @Bean
    public RestTemplate oAuth2RestTemplate(OAuth2AuthorizedClientManager authorizedClientManager) {
        RestTemplate restTemplate = new RestTemplate();
        // 添加OAuth2请求拦截器,自动注入token
        restTemplate.getInterceptors().add(
            new OAuth2AuthorizedClientHttpRequestInterceptor(authorizedClientManager, "myuser")
        );
        return restTemplate;
    }

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientRepository authorizedClientRepository) {

        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials()
                        .build();

        DefaultOAuth2AuthorizedClientManager authorizedClientManager =
                new DefaultOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientRepository);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }
}

4. 简化Controller实现

直接使用配置好的RestTemplate,无需手动处理token:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/v2/")
public class ApiController {

    private final RestTemplate oAuth2RestTemplate;

    // 构造器注入(推荐)
    public ApiController(RestTemplate oAuth2RestTemplate) {
        this.oAuth2RestTemplate = oAuth2RestTemplate;
    }

    @GetMapping("/protected-data")
    public ResponseEntity<String> getProtectedData() {
        // RestTemplate会自动添加Authorization Header
        ResponseEntity<String> response = oAuth2RestTemplate.getForEntity(
                "https://my-resource-server/v1/resource/1",
                String.class
        );
        return ResponseEntity.ok("Protected data retrieved: " + response.getBody());
    }
}

5. 更新WebSecurity配置(替换过时的WebSecurityConfigurerAdapter)

使用Spring Security 5.7+推荐的SecurityFilterChain,同时保留原有Basic Auth逻辑并启用OAuth2客户端支持:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    private final BasicAuthConfig basicAuthConfig;

    public WebSecurityConfig(BasicAuthConfig basicAuthConfig) {
        this.basicAuthConfig = basicAuthConfig;
    }

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withUsername(basicAuthConfig.getUsername())
                .password(encoder().encode(basicAuthConfig.getPassword()))
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .antMatchers("/v1/**").authenticated()
                        .anyRequest().permitAll()
                )
                .httpBasic() // 保留原有Basic Auth逻辑
                .and()
                .oauth2Client(); // 启用OAuth2客户端支持,让Spring管理token

        return http.build();
    }
}

关键说明

  • OAuth2AuthorizedClientManager会自动处理token的获取、缓存和过期刷新,无需手动干预。
  • 配置的RestTemplate通过拦截器自动在请求中添加Authorization: Bearer {token}头。
  • 新的SecurityFilterChain配置同时兼容原有Basic Auth和OAuth2客户端功能,避免冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:25:06