8

The goal is to attach some data from security context using RequestInterceptor, but the problem, that the calling SecurityContextHolder.getContext().getAuthentication() always returns null even though it is not null (I am sure 100%).

As I understand that's because the Interceptor is created and is being run in other thread.

How could I solve this problem and get actual data from security context?

My service:

@FeignClient(value = "api", configuration = { FeignConfig.class })
public interface DocumentService {

    @RequestMapping(value = "/list", method = RequestMethod.GET)
     DocumentListOperation list();
 }

My FeignConfig class:

@Bean
public RequestInterceptor requestInterceptor() {
    return new HeaderInterceptor(userService);
}

public class HeaderInterceptor implements RequestInterceptor {

    private UserService userService;

    public HeaderInterceptor(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        Authentication a = SecurityContextHolder.getContext().getAuthentication()

        requestTemplate.header("authentication", a.toString());
    }
}

1 Answer 1

6

I managed to figure it out, thanks to the article I found here

Firstly you need to initiliaze HystrixRequestContext HystrixRequestContext.initializeContext();.

You have to create your own Context in which you will store information you need to pass to Hystrix child threads.

Here is example:

public class UserHystrixRequestContext {

    private static final HystrixRequestVariableDefault<User> userContextVariable = new HystrixRequestVariableDefault<>();

    private UserHystrixRequestContext() {}

    public static HystrixRequestVariableDefault<User> getInstance() {
        return userContextVariable;
    }
}

You have to register new concurrency strategy that would wrap Callable interface

@Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

    public CustomHystrixConcurrencyStrategy() {
        HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
    }

    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        return new HystrixContextWrapper<T>(callable);
    }

    public static class HystrixContextWrapper<V> implements Callable<V> {

        private HystrixRequestContext hystrixRequestContext;
        private Callable<V> delegate;

        public HystrixContextWrapper(Callable<V> delegate) {
        this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
            this.delegate = delegate;
        }

        @Override
        public V call() throws Exception {
            HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
            try {
                HystrixRequestContext.setContextOnCurrentThread(this.hystrixRequestContext);
                return this.delegate.call();
            } finally {
                HystrixRequestContext.setContextOnCurrentThread(existingState);
            }
        }
    }
}

So before calling Callable object we set new thread's Context to parent's context.

After that is done you should be able to access your new defined context inside Hystrix child threads

User = UserHystrixRequestContext.getInstance().get();

Hope that will help someone.

1
  • Thanks for this answer. Really helped me.. I think that you can just use a Servlet Filter - so no need to implement a CustomHystrixConcurrencyStrategy ? Mar 7, 2021 at 16:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.