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 ?
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.
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.
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.
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");
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With