이 글은 정수원님의 Infrean 강의를 학습한 내용을 정리하여 작성합니다.
인증 저장소 - SecurityContextHolder, SecurityContext
- SecurityContext
- Authentication 객체가 저장되는 보관소로 필요 시 언제든 Authentication 객체를 꺼내어 쓸 수 있도록 제공되는 클래스이다.
- ThreadLocal에 저장되어 아무 곳에서나 참조가 가능하도록 설계한다.
- 인증이 완료된면 HttpSession에 저장되어 어플리케이션 전반에 걸쳐 전역적인 참조가 가능하다.
- SecurityContextHolder
- SecurityContext 객체 저장 방식
- MODE_THREADLOCAL
- 스레드당 SecurityContext 객체를 할당, 기본값
- MODE_INHERITABLETHREADLOCAL
- 메인 스레드와 자식 스레드에 관해 동일한 SecurityContext를 유지
- MODE_GLOBAL
- 응용 프로그램에서 단 하나의 SecurityContext를 저장한다.
- MODE_THREADLOCAL
- SecurityContextHodler.clearContext()
- SecurityContext 기존 정보 초기화
- SecurityContext 객체 저장 방식
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication()
- 사용자가 로그인을 시도한다.
- 서버에서 쓰레드를 생성한다.
- 각 쓰레드마다 ThreadLocal이 생성된다.
- 쓰레드가 인증 처리를 수행한다.
- 만약 인증이 실패하면 SecurityContextHolder.clearContext()를 호출해 SecurrityContextHolder 내 SecurityContext 정보를 초기화 한다.
- 만약 인증에 성공하면 인증 필터는 SecurityContextHolder 내 SecurityHolder 객체에 인증에 성공한 Auhtentication 객체를 담는다.
- 최종적으로 SecurityContext는 HttpSession에 저장된다.
참고
현재 스프링 시큐리티 5.7.6 버전에서는 SecurityContext 저장 방식을 다음과 같이 4개를 지원한다.
실습
- 다음과 같이 컨트롤러를 생성한다.
- SecurityContextHolder.getContext().getAuthentication()을 호출해 생성된 Authentication 객체를 참조할 수 있다.
- 또한 인증 후 HttpSession에 저장된 Authentication 객체를 참조할 수 있다.
@GetMapping("/")
public String index(HttpSession session) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SecurityContext context = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication authentication1 = context.getAuthentication();
return "home";
}
- 생성된 authentication과 authentication1이 서로 동일한 것을 확인할 수 있다.
- 서로 다른 쓰레드 간에 SecurityContext 객체는 서로 공유되지 않는다.
- 다음과 같이 새로운 쓰레드를 생성해 main 쓰레드의 SecurityContext 객체와 공유되지 않음을 확인한다.
@GetMapping("/thread")
public String thread() {
new Thread(
new Runnable() {
@Override
public void run() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
}
}
).start();
return "thread";
}
- authentication값이 null인 것을 확인할 수 있다.
- 이러한 이유는 사용자가 인증 후 생성한 Authentication 객체는 main 쓰레드 로컬에 저장했기 때문이다.
- SecurityContext 객체 저장 방식 중 MODE_THREADLOCAL은 main 쓰레드와 자식 쓰레드 간에 Authentication 객체를 공유할 수 없다는 문제가 존재한다.
- 만약 공유하고 싶다면 MODE_INHERITABLETHREADLOCAL 방식을 사용해야 한다.
- 다음과 같은 방법으로 ThreadLocal에 Authentication 객체 저장 방식을 변경할 수 있다.
- MODE_THREADLOCAL(기본) -> MODE_INHERITABLETHREADLOCAL
- MODE_INHERITABLETHREADLOCAL 방식을 적용한 경우 자식 쓰레드의 Authentication 값은 다음과 같다.
- 이전과 달리 Authentication 객체가 존재하는 것을 확인할 수 있다.
'스프링 시큐리티 > 스프링 시큐리티 주요 아키텍처 이해' 카테고리의 다른 글
인증 흐름 이해 - AuthenticationFlow (0) | 2023.01.31 |
---|---|
인증 저장소 필터 - SecurityContextPersistenceFilter (0) | 2023.01.31 |
인증 개념 이해 - Authentication (0) | 2023.01.30 |
필터 초기화와 다중 보안 설정 (0) | 2023.01.30 |
위임 필터 및 필터 빈 초기화 - DelegatingProxyChain, FilterChainProxy (0) | 2023.01.28 |