Dnyaneshwar Jadhav
Dnyaneshwar Jadhav

Reputation: 353

FeignClient logs printing two configured Interceptor called, this is confusion to identify which one is actual at runtime

I am using FeignClient for Rest API calls, here is Use case as explained below.

I am having 2 different Services which are Authorized with Basic Authentication, with both different Authentications.

enter image description here

Service-1(SpringBoot Microservice) running with below configuration

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
@EnableWebSecurity
public class ApplicationConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private BasicAuthenticationPoint basicAuthenticationPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/", "/api/**").permitAll()
        .anyRequest().authenticated();
        http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("XYZ").password("PQR").roles("USER");
    }
}

Service-2(SpringBoot Microservice) running with below configuration

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
@EnableWebSecurity
public class ApplicationConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private BasicAuthenticationPoint basicAuthenticationPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/", "/api/**").permitAll()
        .anyRequest().authenticated();
        http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("abc").password("123").roles("USER");
    }
}

And from third Microservice I am trying to connect each with following code base, FeignClientConfiguration1


import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import javax.servlet.ServletRequestListener;

@Configuration
public class FeignClientConfiguration1 {

    @Autowired
    private Environment env;

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        System.out.println("Config-1");
        return new BasicAuthRequestInterceptor("XYZ", "PQR");
    }

    @Bean
    public RequestInterceptor bearerTokenRequestInterceptor() {
        return (RequestTemplate template) -> template.header(HttpHeaders.ACCEPT, String.format(MediaType.APPLICATION_JSON_VALUE));
    }

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

FeignClientConfiguration2


import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import javax.servlet.ServletRequestListener;

@Configuration
public class FeignClientConfiguration2 {

    @Autowired
    private Environment env;

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        System.out.println("Config-2");
        return new BasicAuthRequestInterceptor("abc", "123");
    }

    @Bean
    public RequestInterceptor bearerTokenRequestInterceptor() {
        return (RequestTemplate template) -> template.header(HttpHeaders.ACCEPT, String.format(MediaType.APPLICATION_JSON_VALUE));
    }    
}

My Feign Clients are as follows FeignClient1


import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import com.config.FeignClientConfiguration1;

@FeignClient( url = "http://localhost:8081", name = "FeignClient1", configuration = FeignClientConfiguration1.class)
public interface FeignClient1 {

    @GetMapping("/api/hello/{name}")
    ResponseEntity<Object> greetingMessage(@PathVariable String name);

}

FeignClient1


import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import com.config.FeignClientConfiguration1;

@FeignClient( url = "http://localhost:8082", name = "FeignClient2", configuration = FeignClientConfiguration2.class)
public interface FeignClient2 {

    @GetMapping("/api/hello/{name}")
    ResponseEntity<Object> greetingMessage(@PathVariable String name);

}

During calling any of methods from my controller i.e.

@RestController
@RequestMapping(TEST_SERVICE_CONTROLLER_URL)
public class UtilityTestController {
    
    @Autowired
    private FeignClient1 client1;
    
    @Autowired
    private FeignClient2 client2;
    
    
    @GetMapping(value = "/check1", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> test() {
        return new ResponseEntity<>(client1.greetingMessage("TestV1"), null, HttpStatus.OK);
    }

    @GetMapping(value = "/check2", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> test2() {
        return new ResponseEntity<>(client2.greetingMessage("TestV2"), null, HttpStatus.OK);
    }
}

My loggers are

2022-01-05 23:06:09.961 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] ---> GET http://localhost:8081/api/hello/TestV1 HTTP/1.1
2022-01-05 23:06:09.961 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] Accept: application/json
2022-01-05 23:06:09.961 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] Authorization: Basic Y2hhbmRhbmEyOmNoYW5kYW5hMg==
2022-01-05 23:06:09.961 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] Authorization: Basic Y2hhbmRhbmE6Y2hhbmRhbmE=
2022-01-05 23:06:09.961 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] ---> END HTTP (0-byte body)
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] <--- HTTP/1.1 200 (12ms)
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] cache-control: no-cache, no-store, max-age=0, must-revalidate
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] content-type: application/json;charset=UTF-8
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] date: Wed, 05 Jan 2022 17:36:09 GMT
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] expires: 0
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] pragma: no-cache
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] set-cookie: JSESSIONID=2E037D8263A9DAC3D1F8E3957A3C4C54; Path=/; HttpOnly
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] transfer-encoding: chunked
2022-01-05 23:06:09.974 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] x-content-type-options: nosniff
2022-01-05 23:06:09.975 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] x-frame-options: DENY
2022-01-05 23:06:09.975 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] x-xss-protection: 1; mode=block
2022-01-05 23:06:09.975 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] 
2022-01-05 23:06:09.975 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] {"player":"TestV1","message":"Hello V2TestV1"}
2022-01-05 23:06:09.975 DEBUG 19552 --- [nio-8080-exec-3] c.m.e.o.test.gateways.FeignClient1       : [FeignClient1#greetingMessage] <--- END HTTP (46-byte body)

At both occasion in logs there are twice Authorization part is logged. So, here I am bit confused whether or not it is picking up correct interceptor or not.

My Confusions are

  1. Why it is showing twice in loggers, does it going through each interceptors from different configurations ?
  2. Will this possible to silent un related Interceptors ?
  3. Does Feign client going through all of Interceptors that are registered in each configurational classes ?

Note: Although I am getting valid response, means it is cracking through with correct configured BasicAuth w.r.t. each methods.

Upvotes: 2

Views: 1631

Answers (1)

Arnold Galovics
Arnold Galovics

Reputation: 3416

Since you are marking FeignClientConfiguration1 and FeignClientConfiguration2 classes with the @Configuration annotation, they'll be picked up "globally" for the Spring context which essentially means those beans relevant for Feign will be applied to all Feign clients.

I see you specified the configuration attribute on your @FeignClient annotation but that won't "undo" the global configuration.

The way to go is to remove the @Configuration annotation from FeignClientConfiguration1 and FeignClientConfiguration2 and use the @FeignClient configuration attribute only.

Upvotes: 2

Related Questions