Integrate Spring Cloud Gateway with OAuth2 Authorization Server through Eureka - Stack Overflow

admin2025-04-17  3

I have a working Spring Cloud Gateway OAuth2 Client which is forwarding requests to OAuth2 Resource Servers behind Eureka and I would like to take the scalability a step further by enabling it to discover the Authorization Server as well through Eureka.

Basically, the problem is that in my current configuration is that my application.yml contains the following piece of code:

  security:
    oauth2:
      client:
        provider:
          authorization-server:
            issuer-uri: ${ISSUER_URI} # http://localhost:9000/auth
            authorization-uri: ${AUTHORIZATION_URI} # http://localhost:9000/auth/oauth2/authorize

With such a configuration, if the Authorization Server goes under heavy load and scales out, it wouldn't be possible to select a different instance to forward requests by the gateway.

What I tried next is to move the configuration into Java code in order to use a DiscoveryClient. What I came up with is the following:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {

    @Autowired
    private DiscoveryClient discoveryClient;

    // ...

    private String getAuthorizationServerAddress() {
        return this.discoveryClient.getInstances("authorization-server")
                .get(0)
                .getUri()
                .toString();
    }

    @Bean
    public ReactiveClientRegistrationRepository reactiveClientRegistrationRepository() {
        var authorizationServerAddress = this.getAuthorizationServerAddress();

        var clientRegistration = ClientRegistrations.fromOidcIssuerLocation(authorizationServerAddress + "/auth")
                .registrationId(this.applicationName)
                .authorizationUri(this.applicationApiUrl + "/auth/oauth2/authorize")
                .clientId(this.applicationName)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .clientSecret(this.clientSecret)
                .redirectUri(this.applicationBaseUrl + "/oauth2/login/code/" + this.applicationName)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .scope(Set.of("openid", "profile", "offline_access"))
                .build();

        return new InMemoryReactiveClientRegistrationRepository(clientRegistration);
    }

    @Bean
    public ReactiveOAuth2AuthorizedClientService authorizedClientService() {
        return new InMemoryReactiveOAuth2AuthorizedClientService(this.reactiveClientRegistrationRepository());
    }

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http,
                                                            ReactiveClientRegistrationRepository clientRegistrationRepository,
                                                            ReactiveOAuth2AuthorizedClientService oAuth2AuthorizedClientService,
                                                            ServerOAuth2AuthorizationRequestResolver resolver) {
        // ...
        
        http.oauth2Login(auth -> auth
                .authenticationMatcher(new PathPatternParserServerWebExchangeMatcher("/oauth2/login/code/{registrationId}"))
                .authenticationSuccessHandler(this.customLoginSuccessHandler)
                .authorizationRequestResolver(resolver)
                .clientRegistrationRepository(clientRegistrationRepository)
                .authorizedClientService(oAuth2AuthorizedClientService)
        );

        // ...

        return http.build();
    }

Now this setup allows me to get the Authorization Server IP from Eureka but it only does at boot, meaning that every request the gateway will serve while it's on will be directed to that particular instance... which can easily be terminated over time if scaling-in happens.

I read that the solution could be to provide a custom WebClient bean with @LoadBalanced annotation, but after my tests it looks like the gateway doesn't use it in the OAuth2 flow.

I tried to find more hints online but looks like I'm either providing the wrong search query or that the problem is still open.

The most generic solution would be to set something like this below

  security:
    oauth2:
      client:
        provider:
          authorization-server:
            issuer-uri: http://authorization-server/auth
            authorization-uri: http://authorization-server/auth/oauth2/authorize

or at least intercept the requests before they are dispatched in order to modify the requested URI through DiscoveryClient.

Can anyone point me to the right direction? Thanks!

转载请注明原文地址:http://anycun.com/QandA/1744846361a88438.html