spring 安全性是否提供开箱即用的功能来从资源服务器检索和使用 OAuth2 令牌

Does spring security provide out of the box feature to retrieve and use OAuth2 token from a resource server

我们有一个 Springboot 应用程序(比方说 microservice-A),我们需要添加一个带有 OAuth2 令牌的 HTTP 授权 header 来访问我们的其中一个其他微服务(假设 microservice-B)。我们还说我们可以通过向相同的 microservice-B.

发送带有 Grant_type、范围和基本身份验证用户名和密码的 HTTP POST 请求来检索此 OAuth2 令牌

现在我的疑问是,我们是否有来自 Spring 安全性的任何开箱即用的支持,以便在它过期时自动从 microservice-B 检索此 OAuth2 令牌并发送后续的 HTTP 请求。或者这根本不需要,我应该首先通过从 microservice-A 发送普通的 HTTP POST 请求来检索 OAuth2 令牌,然后发送后续请求。 (这样我可能每次发送请求或保存令牌并在它过期时检索它时都必须检索 OAuth2 令牌)

Microservice-A 是“客户” Microservice-B是“资源服务器”

使用 org.springframework.boot:spring-boot-starter-oauth2-client 找到了解决方案。以下是配置基于 OAUTH2 的 WebClient 所需的配置,该 WebClient 可以自动从 auth-server (Microservice-B) 获取 OAUTH2 令牌并访问 resource-server (Microservice-B).

application.properties

oauth2.client.registration.pgw.scope=all
oauth2.client.registration.pgw.client-id=client
oauth2.client.registration.pgw.client-secret=secret
oauth2.client.provider.pgw.token-uri=http://localhost:8082/oauth/token

Oauth2ClientConfiguration.java

@Configuration
public class Oauth2ClientConfiguration {
        
    @Bean
    public ReactiveClientRegistrationRepository getRegistration(
            @Value("${oauth2.client.provider.pgw.token-uri}") String tokenUri,
            @Value("${oauth2.client.registration.pgw.client-id}") String clientId,
            @Value("${oauth2.client.registration.pgw.client-secret}") String clientSecret,
            @Value("${oauth2.client.registration.pgw.scope}") String scope) {
        
        ClientRegistration registration = ClientRegistration
                                                .withRegistrationId(OAUTH2_CLIENT_REGISTRATION_ID)
                                                .tokenUri(tokenUri)
                                                .clientId(clientId)
                                                .clientSecret(clientSecret)
                                                .authorizationGrantType(CLIENT_CREDENTIALS)
                                                .scope(scope)
                                                .build();
        
        return new InMemoryReactiveClientRegistrationRepository(registration);
    }
    
    @Bean
    public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
        InMemoryReactiveOAuth2AuthorizedClientService clientService = 
                new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
        
        AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = 
                new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, clientService);
        
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = 
                new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        oauth.setDefaultClientRegistrationId(OAUTH2_CLIENT_REGISTRATION_ID);
        
        return WebClient.builder().filter(oauth).build();
    }

}

然后我们可以使用此 WebClient bean 将 HTTP 请求发送到 resource-server,后者将负责获取和管理 OAUTH2 令牌

webClient.get().uri("http://localhost:8080/api/private").retrieve().bodyToMono(String.class).block();