Aritz
Aritz

Reputation: 31679

Integrate Spring Cloud load balancing with KeycloakRestTemplate

I have a microservice landscape configured with Spring Cloud discovery so I'm able to access other service instances just using their id's:

public class MyClass {

    @Autowired
    @LoadBalanced
    private RestTemplate restTemplate;

    public String doOtherStuff() {
        String results = restTemplate.getForObject("http://stores/stores", String.class);
        return results;
    }
}

Now I want to access a service which needs OAuth2 authorization. I use a Keycloak server in order to provide it and Keycloak already provides an adapter with an specific KeycloakRestTemplate. Anyway, how to enhance it with load balancing?

Upvotes: 1

Views: 1341

Answers (2)

qruk
qruk

Reputation: 11

your solution is not realy good, because

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@LoadBalanced
public KeycloakRestTemplate keycloakRestTemplate(
        KeycloakClientRequestFactory keycloakClientRequestFactory,
        LoadBalancerInterceptor interceptor) {
    KeycloakRestTemplate result = new KeycloakRestTemplate(
        keycloakClientRequestFactory);
    // Add the interceptor for load balancing
    result.getInterceptors().add(interceptor);
    return result;
}

not has worked, becouse you have got exception

The dependencies of some of the beans in the application context form a cycle:
...
┌─────┐
|  keycloakRestTemplate defined in class path resource [...]
↑     ↓
|  ribbonInterceptor defined in class path resource [org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration$LoadBalancerInterceptorConfig.class]
↑     ↓
|  org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration     (field private java.util.List org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration.restTemplates)
└─────┘

What do you have to do?

@Bean
@LoadBalanced
public KeycloakRestTemplate keycloakRestTemplate(
        KeycloakClientRequestFactory keycloakClientRequestFactory) {
    return new KeycloakRestTemplate(keycloakClientRequestFactory);
}

without @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) then you get singleton which you cane use like this

@Autowired
protected KeycloakRestTemplate restTemplate;

or you can define restTemplate like prototype

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@LoadBalanced
public KeycloakRestTemplate keycloakRestTemplate(
        KeycloakClientRequestFactory keycloakClientRequestFactory) {
    return new KeycloakRestTemplate(keycloakClientRequestFactory);
}

and then use like this

@Autowired
@LoadBalanced
protected KeycloakRestTemplate restTemplate;

Edit: The solution of Xtreme Biker has not worked with SpringBoot 2 and Keycloak 6 because of problem with cycle, my first proposition is not threads/sesions save, the second does not work because of been will be createing before run @LoadBalanced and the restTemplate wchich is created based on prototype is to without sets interceptor :|

Upvotes: 0

Aritz
Aritz

Reputation: 31679

We need to create a specific KeycloakRestTemplate which will use a LoadBalancerInterceptor:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @LoadBalanced
    public KeycloakRestTemplate keycloakRestTemplate(
            KeycloakClientRequestFactory keycloakClientRequestFactory,
            LoadBalancerInterceptor interceptor) {
        KeycloakRestTemplate result = new KeycloakRestTemplate(
            keycloakClientRequestFactory);
        // Add the interceptor for load balancing
        result.getInterceptors().add(interceptor);
        return result;
    }

    //More configurations for keycloak

}

So there's the chance of getting an Authorized / LoadBalanced template:

@Autowired
@LoadBalanced
protected KeycloakRestTemplate restTemplate;

See also:

Upvotes: 2

Related Questions