목차
들어가기
앞서 [#1]에서 간략하게 어떻게 필터들이 동작하고, 시큐리티가 동작하는지를 확인할 수 있었다.
이 속에서 우리는 Context라는 것을 알게 되었다. 시큐리티는 사용자의 정보를 담기위해 Security Context라는 것을 만들어서 사용자의 Authenticaton(인증) 객체를 확인하고, 저장하는 과정을 가지게 되며, 이 인증된 객체를 전역에서 꺼내쓸 수 있다. 이러한 이유는 인증된 객체는 ThreadLocal에 저장되어 있기 때문이라고 간단하게 언급했었는데, 해당 객체에 관한 인증이 완료되면 HttpSession에 저장되어 애플리케이션 전역에서 참조가 가능한 것이다. 그럼 어떻게 내부적으로 동작을 하는 것일까? 궁금해졌다.
Security 클래스 속에 getCurrentMemberEmail() 메서드이다. 해당 메서드를 호출하게 되면 어디에서든 인증객체의 name을 가지고 올 수 있다. (여기서 getName() 사용자 ID값을 말한다 -> pk값이 아니라 사용자가 로그인 하는 ID )
나는 이 ContextHolder가 생성되는 시점에 Bean으로 등록되어서 전역 메모리에 올라가니까 어디에서든지 참조 가능하지 않을까? 라는 생각을 해봤다.
Spring Security Context Holder
일단 시큐리티는 내부적으로 이러한 필터를 거치게 된다. 개발자가 작성한 필터를 거치면서 내부적으로 문제가 있는지 없는지 확인을 하게되고, 이상이 있으면 해당 필터에서 처리한 방법으로 뭐 예외를 던진다던지, 그런 방식으로 필터를 거치고 FilterChain으로 엮여있는 doFilter를 통해 다음 필터로 이동하게 된다.
이 때 위 코드를 보면 토큰을 이용해서 인증 객체를 찾고, 그 객체를 setAuthentication()속에 넣어서 처리를 위임하며,
시큐리티 컨텍스트 홀더(Security Context Holder)는 SecurityContextHolderStrategy라는 객체에 모든 처리를 위임한다.
SecurityContextHolder를 들어가서 맨 위 설명과 아래 메서드를 확인해보면 다음과 같다.
간단하게 이 설명을 직독하자면 현재 스레드와 시큐리티 컨텍스트를 연결하는데, 시큐리티 컨택스트 홀더 전략(Security ContextHolderStrategy)의 인스턴스를 위임하는 일련의 스태틱 메서드를 제공한다. 이 클래스의 목적은 편안한 방식을 제공하는 것인데, JVM이 사용해야하는 전략을 지정하는 편리한 방법을 제공하는 (이하는 생략..)
아하! 여기서 확인가능한 것처럼, 이 클래스는 편리한 방식을 제공한다. 어떤방식? 다양한 static 메소드를 제공하고, 해당 메소드들은 내부적으로 SecurityContextHolderStrategy 에게 위임을 처리하고!
(아니 계속 역할을 떠미네?) 그럼 실세는 결국 SecurityContextHolderStrategy 이 친구네? ( 이 친구가 처리를 함 )
SecurityContextHolder를 초기화 하게되면, 아래 그림의 코드의 메소드가 호출되고, 내부적으로 Strategy를 정하는 방식이며, 여러 전략을 사용할 수 있는데, default 값이 ThreadLocal 방식이다
앞서 설명한 것처럼 Security Context Holder는 Security Context Holder Stratgy 라는 객체에 모든 처리를 위임한다고 했는데, 이 SecurityContextHolderStrategy는 Static으로 선언이 되어 있음을 직접 확인할 수 있었다.
(윗 MODE_THREADLOCAL 는 스레드 하나당 Security context 객체를 할당하는 전략)
그럼 컨텍스트 홀더가 로딩되는 시점에 이 전략이 정해질 것이고, 해당 전략으로 ThreadLocalSecurityContextHolder전략을 사용하는 것을 윗 코드를 통해 확인할 수 있다. (전략에 따라 SecurityContext의 저장 방식이 다를 것이지만, 일반적으로 ThreadLocal에 저장한다. 그래서 우리는 전역에서 인증객체를 꺼내 사용할 수 있다는 점!)
ThreadLocalSecurityContextHolderStrategy는 내부적으로 위와 같이 로직을 담고있다.
먼저 시큐리티 컨택스트 객체를 스레드 하나당 생성한다는 전략 -> ThreadLocalSecurityContextHolderStrategy
이 클래스(ThreadLocalSecurityContextHolderStrategy)를 열어보면 아래와 같이 필드를 하나 가지고 있다.
또한 윗 코드에서 확인할 수 있는 것처럼 새로운빈context를 만들 때, 리턴 값으로 new SecurityContextImpl을 통해 시큐리티 컨텍스트를 생성하는데, 해당 메서드를 타고 들어가보면 인증과 관련된 get, set 메서드들이 있다.
시큐리티 컨택스트 홀더는 ThreadLocal을 활용해 인증과 관련된 여러 정보를 저장하고, 해당 스레드에서는 같은 인증 정보에 접근할 수 있다. 요청 처리가 마무리된 스레드의 인증 정보는 FilterChainProxy가 지운다.
마무리
어렵다.. 어렵다 어렵다... 아직 이해가 부족하다.
글을 읽으면서, 나름 정리를 하려고 해보았는데도 아직은 크게 막 와닿지 않았다.
어떻게 SecurityContextHolder가 정보를 우리에게 제공해주고, 그럼 어떻게 저장되고, 연관된 기능들이 어떤 로직을 담고 있는지 매우 궁금했는데, 그래도 직접 눈으로 확인하고 여러 정보를 조합해서 학습함으로써 조금의 궁금증은 풀리게 되었다.
그러나 아직 완벽하게 이해한 것은 아니니 조금 더 눈여겨 볼 필요가 있다고 생각한다.
아직 완벽한 이해를 하지 못했다는점이 아쉽다...
참고 :
https://velog.io/@dailylifecoding/spring-security-authentication-registry
https://yousrain.tistory.com/13
https://00hongjun.github.io/spring-security/securitycontextholder/
https://catsbi.oopy.io/f9b0d83c-4775-47da-9c81-2261851fe0d0
'스프링' 카테고리의 다른 글
@Mappings 사용하기 (0) | 2023.12.13 |
---|---|
[#1] Spring Security - 시큐리티는 무엇이고, Filter는 무엇인지 (0) | 2022.12.29 |
[10분 테코톡] - @JDK Dynamic Proxy & CGLIB (0) | 2022.12.22 |
[10분 테코톡] - @Transactional (0) | 2022.12.21 |
Spring- Lombok의 이해와 @Annotation (계속 추가합니다.) (0) | 2022.12.14 |