BackEnd/Spring Security

[Spring Security] SecurityContextHolder, SecurityContext

샤아이인 2022. 8. 25.

본 글은 Spring Security docs 와 여러 블로그 들을 참고하고, 공부하면서 요약하였습니다.

 

https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-securitycontextholder

 

Servlet Authentication Architecture :: Spring Security

ProviderManager is the most commonly used implementation of AuthenticationManager. ProviderManager delegates to a List of AuthenticationProviders. Each AuthenticationProvider has an opportunity to indicate that authentication should be successful, fail, or

docs.spring.io

 

1. SecurityContextHolder, SecurityContext

 

 

1) SecurityContext

Authentication 객체가 저장되는 보관소로 필요 시 언제든지 Authentication 객체를 꺼내어 쓸 수 있도록 제공되는 클래스이다.

SecurityContext는 ThreadLocal에 저장되어 아무 곳에서나 참조가 가능하도록 설계된다.

인증이 완료되면 HttpSession에 저장되어 어플리케이션 전반에 걸쳐 전역적인 참조가 가능하다.

 

이때 ThreadLocal은 각 Thread별로 할당된 별도의 공간이다. 따라서 공유되지 않으며, 다른 Thread로부터 공유되지 않는다.

 

2) SecurityContextHolder

SecurityContext 객체를 저장하고 감싸고 있는 wrapper 클래스이다.

SecurityContext객체를 저장하는 방식에는 3가지 MODE가 있다.

 

  • MODE_THREADLOCAL: 각 스레드별로 SecurityContext객체를 할당. default 방식
  • MODE_INHERITABLETHREADLOCAL: 메인 스레드와 자식 스레드에 관하여 동일한 SecurityContext를 유지
  • MODE_GLOBAL: 응용 프로그램에서 단 하나의 SecurityContext를 저장한다.

SecurityContext 와 SecurityContextHolder를 사용하는 코드는 대략 다음과 같다.

SecurityContext context = SecurityContextHolder.createEmptyContext(); 
Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER"); 
context.setAuthentication(authentication);

SecurityContextHolder.setContext(context);

비어있는 SecurityContext를 생성하고, 여기에 인증객체인 Authentication을 저장한다.

이 SecurityContext를 SecurityContextHolder에 저장하면 전역으로 사용이 가능하게 된다.

 

SecurityContextholder.clearContext()를 통해서 SecurityContext기본 정보를 초기화 시킬 수 있다.

 

또한 다음과 같이 인증객체를 어디서든 꺼내어 사용할 수 있다.

Authentication authentication = SecurityContextHolder.getContext().getAuthentication()

 

▶ Flow

1. Login을 사용자가 시도


2. Server가 요청을 받아서 Thread를 생성 (ThreadLocal 할당)


3. thread가 인증 처리 시도 → 인증 객체(Authentication) 생성 


4. (인증 실패) SecurityContextHolder.clearContext() 인증객체 초기화


5. (인증 성공) SecurityContextHolder안의 SecurityContext에 인증객체(Authentication)저장
→ SecurityContextHolder에 필드로 ThreadLocal을 가지고 있다.


6. SecurityContext가 최종적으로는 "SPRING_SECURITY_CONTEXT"라는 이름으로 HttpSession에 저장이 된다.

 

2. 디버깅 해보기

▶ SecurityContextHolder

SecurityContextHolder는 처음에 다음 init 메서드를 호출하게 된다.

빨간 박스안을 보면 위에서 언급한 3가지 전략중 하나를 선택하게 된다.

 

이중에서 ThreadLocalSecurityContextHolderStrategy()가 default 방식이라 선택된다. (설정으로 변경 가능)

▶ ThreadLocalSecurityContextHolderStrategy

ThreadLocalSecurityContextHolderStrategy 클래스의 코드는 위와 같다.

내부에 필드로 contextHolder를 가지고 있다. 여기에 SecurityContext를 저장하게 된다.

 

또한 SecurityContext는 인터페이스 이다. 이를 구현한 구현체는 다음과 같다.

 

▶ SecurityContextImpl

내부에 Authentication 객체를 저장하게 됩니다.

 

참고

https://catsbi.oopy.io/f9b0d83c-4775-47da-9c81-2261851fe0d0

 

스프링 시큐리티 주요 아키텍처 이해

목차

catsbi.oopy.io

 

댓글