WebAsyncManagerIntegrationFilter (Controller layer)예외 (@Async 의 경우. Service layer)ServiceLayer에서도 ThreadLocal 참조 가능하게 하는 방법DelegatingSecurityContextAsyncTaskExecutor
WebAsyncManagerIntegrationFilter (Controller layer)
- Spring MVC Async Request (반환 타입이 Callable) 처리에서 SecurityContext를 공유할수 있게 함
- Callable 객체가 별도의 Thread에서 실행되는데 그럼에도 불구하고 SecurityContext 공유가 가능함
- 아래 실행 로그를 살펴보면, Callable 실행 로직이 다른 쓰레드에서 실행되었음에도 SecurityContext를 제대로 참조했음
- MVC 핸들러 쓰레드 — XNIO-1 task-2
- Callable 실행 쓰레드 — task-1

- 앞에서 살펴본 바에 의하면, SecurityContext는 ThreadLocal 변수를 이용하고 있고, 따라서 다른 쓰레드에서는 SecurityContext를 참조할수 없어야 함
- WebAsyncManagerIntegrationFilter는 MVC Async Request가 처리될 때, 쓰레드간 SecurityContext를 공유할수 있게 해줌
- SecurityContextCallableProcessingInterceptor 클래스를 이용함
- beforeConcurrentHandling() — HTTP 요청을 처리하고 있는 WAS 기본 쓰레드에서 실행
- 해당 메소드 구현의 SecurityContextHolder.getContext() 부분은 ThreadLocal의 SecurityContext 정상적으로 참조함
- 즉, ThreadLocal의 SecurityContext 객체를 SecurityContextCallableProcessingInterceptor 클래스 멤버변수에 할당함 by invoking setSecurityContext( )
- preProcess(), postProcess() — WAS 기본 쓰레드가 아닌 별도 쓰레드에서 실행
- preProcess() : 클래스 멤버변수의 securityContext를 set 해줌
- postProcess( ) : SecurityContextHolder를 클리어 해줌(앞에서 Thread per request에서 보듯이 Thread를 반환할때는 안에 내용물 지우고 주기)
예외 (@Async 의 경우. Service layer)
- 단, 위 기능은 Spring MVC Async Request 처리에서만 적용되며 (즉, Controller 메소드) @Async 어노테이션을 추가한 Service 레이어 메소드에는 해당 안됨

ServiceLayer에서도 ThreadLocal 참조 가능하게 하는 방법
- SecurityContextHolderStrategy 설정값을 기본값
MODE_THREADLOCAL
에서MODE_INHERITABLETHREADLOCAL
으로 변경 - 다른 쓰레드(task-1)에서도 SecurityContext를 참조할 수 있게됨
- SecurityContextHolderStrategy 인터페이스 구현체를 기본값 ThreadLocalSecurityContextHolderStrategy (
MODE_THREADLOCAL
) 에서 InheritableThreadLocalSecurityContextHolderStrategy(MODE_INHERITABLETHREADLOCAL
) 으로 변경함 - SecurityContext 저장 변수를 ThreadLocal 에서 InheritableThreadLocal 타입으로 변경하게됨
- InheritableThreadLocal — 부모 쓰레드가 생성한 ThreadLocal 변수를 자식 쓰레드에서 참조할 수 있음

DelegatingSecurityContextAsyncTaskExecutor
MODE_INHERITABLETHREADLOCAL
을 설정하여 이용하는 것은 그다지 권장할 만한 방법이 아님- Pooling 처리된 TaskExecutor와 함께 사용시 ThreadLocal의 clear 처리가 제대로되지 않아 문제될 수 있음 (예 — ThreadPoolTaskExecutor)
- Pooling 되지 않은 TaskExecutor와 함께 사용해야 함 (예 — SimpleAsyncTaskExecutor)
- DelegatingSecurityContextAsyncTaskExecutor 를 이용하여 SecurityContext를 다른 Thread로 전파하는 것을 조금 더 안전하게 할 수 있음
- 내부적으로 Runnable을 DelegatingSecurityContextRunnable 타입으로 wrapping 처리함
- DelegatingSecurityContextRunnable 객체 생성자에서 SecurityContextHolder.getContext() 메소드를 호출하여 SecurityContext 참조를 획득