어린왕자이야기

쓰레드에 spring-security-context 전파 본문

나의 취미/자바 이야기

쓰레드에 spring-security-context 전파

grandguy 2022. 5. 3. 20:04

스프링 시큐리티의 경우 컨트롤러나 서비스에서 현재 쓰레드 기반의 SecurityContextHolder를 이용해서 Authentication정보를 사용한다.

그러나 이 경우, 다른 쓰레드를 사용하는 경우 SecurityContextHolder가 전파되지 않는다.

이러한 상황에 대비해서 스프링 시큐리티에서는 다양한 유틸리티를 제공하고 있다.

 

1. 스프링에서 관리하는 쓰레드의 경우

@Bean
public InitializingBean initializingBean() {
    return () -> SecurityContextHolder
            .setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}

 

@GetMapping("/bye")
@Async()
public void goodbye() throws InterruptedException {
    SecurityContext context = SecurityContextHolder.getContext();
    String username = context.getAuthentication().getName();

    Thread.currentThread().sleep(10000);

    System.out.println("bye end");
}

2. 스프링이 아니라 사용자가 관리하는 쓰레드의 경우

@GetMapping("/ciao")
public String ciao() throws Exception {
    Callable<String> task = () -> {
        SecurityContext context = SecurityContextHolder.getContext();

        Thread.currentThread().sleep(10_000);

        return context.getAuthentication().getName();
    };
    ExecutorService e = Executors.newCachedThreadPool();
    try {
        var contextTask = new DelegatingSecurityContextCallable<>(task);
        return "Ciao, " + e.submit(contextTask).get() + "!";
    } finally {
        e.shutdown();
    }
}

위와 같이 스프링에서 제공하는 유틸리티 클래스를 사용해서 시큐리티 콘텍스트를 래핑해주어야 한다.

Class Description
DelegatingSecurityContextExecutor Implements the Executor interface and is designed to decorate an Executor object with the capability of forwarding the security context to the threads created by its pool.
DelegatingSecurityContextExecutorService Implements the ExecutorService interface and is designed to decorate an ExecutorService object with the capability of forwarding the security context to the threads created by its pool.
DelegatingSecurityContextScheduledExecutorService Implements the ScheduledExecutorService interface and is designed to decorate a ScheduledExecutorService object with the capability of forwarding the security context to the threads created by its pool.
DelegatingSecurityContextRunnable Implements the Runnable interface and represents a task that is executed on a different thread without returning a response. Above a normal Runnable, it is also able to propagate a security context to use on the new thread.
DelegatingSecurityContextCallable Implements the Callable interface and represents a task that is executed on a different thread and that will eventually return a response. Above a normal Callable, it is also able to propagate a security context to use on the new thread.