Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a request interceptor to a feign client?

I want every time when I make a request through feign client, to set a specific header with my authenticated user.

This is my filter from which I get the authentication and set it to the spring security context:

@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
public class PerformanceApplication {
    @Bean
    public Filter requestDetailsFilter() {
        return new RequestDetailsFilter();
    }

    public static void main(String[] args) {
        SpringApplication.run(PerformanceApplication.class, args);
    }

    private class RequestDetailsFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {

        }

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            String userName = ((HttpServletRequest)servletRequest).getHeader("Z-User-Details");
            String pass = ((HttpServletRequest)servletRequest).getHeader("X-User-Details");
            if (pass != null)
                pass = decrypt(pass);
            SecurityContext secure = new SecurityContextImpl();
            org.springframework.security.core.Authentication token = new UsernamePasswordAuthenticationToken(userName, pass);
            secure. setAuthentication(token);
            SecurityContextHolder.setContext(secure);
            filterChain.doFilter(servletRequest, servletResponse);
        }

        @Override
        public void destroy() {

        }
    }
    private String decrypt(String str) {
        try {
            Cipher dcipher = new NullCipher();

            // Decode base64 to get bytes
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);

            // Decrypt
            byte[] utf8 = dcipher.doFinal(dec);

            // Decode using utf-8
            return new String(utf8, "UTF8");
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
        } catch (UnsupportedEncodingException e) {
        } catch (java.io.IOException e) {
        }
        return null;
    }
}

This is my feign client:

@FeignClient("holiday-client")
public interface EmailClient {
    @RequestMapping(value = "/api/email/send", method = RequestMethod.POST)
    void sendEmail(@RequestBody Email email);
}

And here I have a request interceptor:

@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    private String headerValue;

    public FeignRequestInterceptor() {
    }

    public FeignRequestInterceptor(String username, String password) {
        this(username, password, ISO_8859_1);
    }

    public FeignRequestInterceptor(String username, String password, Charset charset) {
        checkNotNull(username, "username");
        checkNotNull(password, "password");
        this.headerValue = "Basic " + base64encode((username + ":" + password).getBytes(charset));
    }

    private static String base64encode(byte[] bytes) {
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bytes);
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("Authorization", headerValue);
    }
}

I don't know how to configure this interceptor to my client and how to set the header with the username and password. How can I accomplish that ?

like image 219
Gustavo Avatar asked Oct 26 '16 12:10

Gustavo


People also ask

How do you add interceptor in feign client?

Feign provides RequestInterceptor interface that can be used for adding/removing/mutating any part of the request. All we need to do is to create a Bean of type RequestInterceptor inside a config class and provide that configuration to FeignClient.

How do you intercept feign response?

If there is a mechanism to intercept Feign's request object and response object, the request header and response header can be obtained, and the request header and response header can be used to transfer data.

How do you pass a path variable in feign client?

To map the path variable to a method argument in a feign client, we use the @PathVariable annotation from Spring. String getThirdService(@PathVariable(name = "id") int id); Using the annotation as such, OpenFeign will substitute the {id} part of the path with the value of the integer id.


2 Answers

You don't really need your own implementation of the FeignRequestInterceptor as there is already BasicAuthRequestInterceptor in the feign.auth package that does exactly the same.

With this said, you basically have almost everything set up already. All is left to do is to define the basicAuthRequestInterceptor bean with specific username and password:

@Bean
public RequestInterceptor basicAuthRequestInterceptor() {
    return new BasicAuthRequestInterceptor("username", "password");
}
like image 106
Aleksandr Erokhin Avatar answered Sep 28 '22 11:09

Aleksandr Erokhin


I know the thread is a bit old but wanted to give some explanation on what's happening here.

If you'd like to customize your Feign requests, you can use a RequestInterceptor. This can be a custom implementation or you can reuse what's available in the Feign library, e.g. BasicAuthRequestInterceptor.

How to register it? Well, there 2 ways to do it depending on how you use Feign.

If you're using plain Feign without Spring, then you gotta set the interceptor to the Feign builder. An example is here.

Feign.builder()
     .requestInterceptor(new MyCustomInterceptor())
     .target(MyClient.class, "http://localhost:8081");

If you're using Spring Cloud OpenFeign and you use the @FeignClient annotation to construct your clients, then you have to create a bean from your RequestInterceptor by either defining it as a @Component or as a @Bean in one of your @Configuration classes. Example here.

@Component
public class MyCustomInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // do something
    }
}

Also, you can check out one of my articles in this topic, maybe that clears it up better: Customizing each request with Spring Cloud Feign

like image 42
Arnold Galovics Avatar answered Sep 28 '22 09:09

Arnold Galovics