0

I am developing a spring cloud project with Feign and OAuth2.In the project, there are some time-consuming operations and some requests will be sent when these operations is finished. In order to achieve a better user experience, these operations was moved into an asynchronous method(with @Async). But there arise a problem. I added the OAuth2FeignRequestInterceptor as a bean and has make sure that the Feign Client can work properly in the synchronous method(which thread has correct RequestAttributes in RequestContextHolder).

@Configuration
public class SomeConfiguration{
@Bean
    public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext, BaseOAuth2ProtectedResourceDetails resource){
        return new OAuth2FeignRequestInterceptor(oAuth2ClientContext,resource);
    }
}

But if I move these operations into an asynchronous method, there will be throws an exception that scopedTarget.oauth2ClientContext cannot be created due to the absent of RequestContext. I have searched the stackoverflow.com and found a solution: How to enable request scope in async task executor With a RequestContextListener bean and these code, the RequestContextHolder belongs to the child thread would be filled with the parent thread's (the request thread) RequestAttributes. Because the asynchronous method will cost some time before invoke the feign client, the request will be reponded before the feign client be invoked. When the request be responded, the RequestContextListener will reset the RequestAttributes in RequestContextHolder by invoke RequestContextHolder.resetRequestAttributes();(RequestContextListener.java:76) and make the request inside the RequestAttributes inactive. When it finished the time-consuming tasks and try to send something by feign client, the feign client try to get the oAuth2ClientContext from the request and throws the exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: Cannot ask for request attribute - request is not active anymore!

I'm not sure if it is appropriate for OAuth2FeignRequestInterceptor to retrieve the Authorization information from the RequestContext in an asynchronous scenario.

Thank you for reading my issue and hoping for your reply.

JerryYuan
  • 1
  • 1

1 Answers1

-1

If you're using spring, you can bind the spring security context to a sub thread.

SecurityContext context = SecurityContextHolder.getContext();
ExecutorService delegateExecutor = new ExecutorServiceAdapter(this.taskExecutor);
DelegatingSecurityContextExecutorService executor = new DelegatingSecurityContextExecutorService(delegateExecutor, context);
executor.invokeAll(tasks).stream()...

Need to define the taskExecutor bean:

@Configuration
public class ThreadConfig {
@Bean
public TaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(4);
    executor.setMaxPoolSize(10);
    executor.setThreadNamePrefix("task_thread");
    executor.initialize();
    return executor;
}
}

Last, most importantly, you need enable setThreadContextInheritable when the servlet startup:

DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
dispatcherServlet.setThreadContextInheritable(true);
Kunkka
  • 1