• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

SecurityContextHolder 관련 질문이 있습니다!

22.04.07 21:38 작성 조회수 999

1

안녕하세요.

항상 좋은 강의 감사드립니다!

 

SecurityContextholder 관련 질문이 있어 글을 적게 되었습니다.

SecurityContext는 ThreadLocal 기반이고, 이를 전역에서 사용할 수 있도록 Static 변수인 SecurityContextHolder에 저장된다고 이해를 했습니다. (강의 내용을 참고,  혹시.. SecurityContextHolder가 Static 변수가 아니라면 정정해주시면 감사하겠습니다!)

 

여기서 궁금한 부분은... 멀티 쓰레딩 환경입니다.

스프링 MVC는 결국 요청마다 쓰레드가 할당되는 쓰레딩풀 환경이라 멀티 쓰레드로 동작을 하고 있는 것으로 알고 있습니다.

 

그렇다면 동시에 사용자로부터 인증 요청이 온다면, 동시에 SecurityContextHolder에 SecurityContext가 각각 저장된다는 것인데.. 이런 환경에서 어떻게 동작하는지 잘 이해하기가 어렵습니다.

 

예를 들어 동시에 인증 요청이 오게 되면, SecurityContextHolder의 동시성 문제는 어떻게 처리되는 걸까요? 

 

항상 좋은 강의 감사드립니다

좋은 하루 되세요! 

 

 

답변 1

답변을 작성해보세요.

7

SecurityContextHolder 은 SecurityContext 를 ThreadLocal 에 저장하고 있습니다.

SecurityContextHolder 는 전략패턴에 따라 기본값은 ThreadLocalSecurityContextHolderStrategy 클래스를 사용합니다.

final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal();

ThreadLocalSecurityContextHolderStrategy() {
}

public void clearContext() {
contextHolder.remove();
}

public SecurityContext getContext() {
SecurityContext ctx = (SecurityContext)contextHolder.get();
if (ctx == null) {
ctx = this.createEmptyContext();
contextHolder.set(ctx);
}

return ctx;
}
......

.....
}

코드를 보시면 contextHolder 가 ThreadLocal 이고 contextHolder.get() 과 contextHolder.set(ctx) 를 통해 SecurityContext 객체를 저장하고 있습니다.

여기서 ThreadLocal 내부를 잠시 들여다 보겠습니다.

public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

ThreadLocal 의  get() 메소드인데 보시면 현재 접속해 있는 Thread 를 참조합니다.

즉 각 사용자에게 할당된 스레드입니다.

그리고 각 스레드마다 고유하게 할당된 ThreadLocal 인 this 를 키로 해서 어떤 값(여기서는 SecurityContext) 를 얻고 있습니다.

그리고 set() 메소들입니다.

public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
}

역시 현재 접속해 있는 스레드를 참조하고 해당 스레드만 가지고 있는 TheadLocal 인 this 를 키로 해서 어떤 값 즉 SecurityContext 를 맵에 저장하고 있습니다.

그렇기 때문에 비록 SecurityContextHolder 가 static 한 ThreadLocal 를 참조하고 있지만 ThreadLocal 내부적으로는 각 스레드마다 자신만의 ThreadLocal 을 키로 해서 SecurityContext 값을 저장 및 조회하고 있기 때문에 스레드에 안전하게 됩니다.