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

Spring Security 5中无Spring OAuth的Feign服务间通信配置咨询

解决Spring Security 5资源服务器中Feign的Client Credentials令牌获取与注入问题

在纯Spring Security 5环境下,我们可以借助spring-security-oauth2-client模块来实现client_credentials授权类型的令牌获取,同时自定义Feign拦截器完成令牌注入。以下是具体实现步骤:

1. 配置客户端注册与令牌管理

首先,我们需要配置授权服务器信息和客户端凭证,同时创建负责令牌获取、刷新的核心组件OAuth2AuthorizedClientManager:

@Configuration
public class OAuth2ClientConfig {

    // 从配置文件绑定客户端信息
    @Bean
    public ClientRegistration clientRegistration(
            @Value("${security.oauth2.client.client-id}") String clientId,
            @Value("${security.oauth2.client.client-secret}") String clientSecret,
            @Value("${security.oauth2.client.access-token-uri}") String tokenUri) {
        return ClientRegistration.withRegistrationId("service-client")
                .clientId(clientId)
                .clientSecret(clientSecret)
                .tokenUri(tokenUri)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .build();
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository(ClientRegistration clientRegistration) {
        return new InMemoryRegisteredClientRepository(clientRegistration);
    }

    // 配置令牌管理器,自动处理令牌的获取、缓存与刷新
    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientService authorizedClientService) {
        OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder
                .builder()
                .clientCredentials()
                .build();

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

        return authorizedClientManager;
    }
}

2. 自定义Feign请求拦截器

替换原Spring OAuth提供的OAuth2FeignRequestInterceptor,实现一个自定义拦截器,通过OAuth2AuthorizedClientManager获取令牌并注入请求头:

@Component
public class ClientCredentialsFeignInterceptor implements RequestInterceptor {

    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_TOKEN_PREFIX = "Bearer ";

    private final OAuth2AuthorizedClientManager authorizedClientManager;

    public ClientCredentialsFeignInterceptor(OAuth2AuthorizedClientManager authorizedClientManager) {
        this.authorizedClientManager = authorizedClientManager;
    }

    @Override
    public void apply(RequestTemplate template) {
        // 构造client_credentials授权的请求参数
        OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("service-client")
                .principal(new AnonymousAuthenticationToken("feign-client", "feign-client", Collections.emptyList()))
                .build();

        // 获取授权客户端(自动处理令牌获取/过期刷新)
        OAuth2AuthorizedClient authorizedClient = authorizedClientManager.authorize(authorizeRequest);

        if (authorizedClient != null && authorizedClient.getAccessToken() != null) {
            String tokenValue = authorizedClient.getAccessToken().getTokenValue();
            template.header(AUTHORIZATION_HEADER, BEARER_TOKEN_PREFIX + tokenValue);
        }
    }
}

3. 配置Feign使用自定义拦截器

你可以选择两种方式让Feign使用这个拦截器:

全局配置(所有Feign客户端生效)

@Configuration
public class FeignGlobalConfig {

    @Autowired
    private ClientCredentialsFeignInterceptor clientCredentialsFeignInterceptor;

    @Bean
    public RequestInterceptor feignRequestInterceptor() {
        return clientCredentialsFeignInterceptor;
    }
}

单个客户端配置(仅指定Feign客户端生效)

在Feign客户端接口上绑定专属配置类:

@FeignClient(name = "resource-server-b", configuration = FeignClientConfig.class)
public interface ResourceServerBClient {
    // 定义调用资源服务器B的接口方法
}

// 专属配置类
@Configuration
public class FeignClientConfig {

    @Autowired
    private ClientCredentialsFeignInterceptor clientCredentialsFeignInterceptor;

    @Bean
    public RequestInterceptor requestInterceptor() {
        return clientCredentialsFeignInterceptor;
    }
}

4. 配置文件复用与说明

原有的yaml配置可以直接复用,不需要大幅修改:

security:
  oauth2:
    client:
      client-id: service-id
      client-secret: secret
      access-token-uri: http://localhost:8081/oauth/token

关键细节说明

  • OAuth2AuthorizedClientManager会自动处理令牌的缓存和过期刷新,无需手动维护令牌生命周期;
  • 拦截器中使用匿名身份作为principal即可,因为client_credentials授权不需要用户上下文;
  • 确保项目依赖中引入了spring-security-oauth2-client和spring-cloud-starter-openfeign(Spring Cloud环境下)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 00:17:33