정수원님의 강의 스프링 시큐리티 완전 정복 [6.x 개정판] 보면서 공부한 내용입니다.
SecurityContextRepository / SecurityContextHolderFilter
SecurityContextRepository
- 스프링 시큐리티에서 사용자가 인증을 한 후 사용자의 인증을 유지하기 위해 사용하는 클래스
- 사용자가 인증을 하게 되면 사용자의 인증 정보와 권한이 SecurityContext 에 저장되고 HttpSession을 통해 요청 간 영속이 이루어지는 방식
⭐ 인증 요청
- 사용자가 인증 요청하면 AuthenticationFilter가 인증 요청을 받아 사용자의 인증을 처리한다
- 사용자의 인증이 성공하면 인증정보를 SecurityContext에 저장한다
- SecurityContext에는 Authentication 인증 객체(user, authorty 등)가 저장된다
- 인증 상태를 유지하기 위해 SecurityContext를 명시적으로 저장소에 보관한다 (2가지 방법을 제공한다 ex: 세션에 저장하는 방식)
- SecurityContext를 저장하는 구현체인 SecurityContextRepository에 정보를 보관한다
- HttpSession에 SecurityContext를 저장하면 이후에는 요청할 때마다 세션으로부터 참조하여 요청 간의 연속이 이루어진다
⭐ 인증 후 요청
- SecurityContextFilter가 사용자가 이전에 SecurityContext를 제작했는지 아닌지 확인한다
- SecurityContextRepository로부터 SecurityContext를 로드한다
- HttpSession으로부터 컨텍스트 존재를 확인한 뒤 컨텍스트를 가져온다
- SecurityContext안의 Authentication이 null이 아닌 경우 사용자가 인증을 한 상태라는 것을 확인할 수 있다
💡 Authentication 타입이 Anonymous 인 경우는 제외한다
인터페이스 구현체
-
DelegatingSecurityContextRepository : RequestAttributeSecurityContextRepository 와 HttpSessionSecurityContextRepository 를 동
시에 사용할 수 있도록 위임된 클래스로서 초기화 시 기본으로 설정된다
-
HttpSessionSecurityContextRepository : HttpSession에 보안 컨텍스트를 저장한다. 사용자의 세션이 살아있는 동안 인증 요청이 끝난 후에 또 다시 요청을 할 경우에도 컨텍스트 영속성을 유지한다
💡 세션이 끝나는 순간 : timeout / 어플리케이션 종료
-
RequestAttributeSecurityContextRepository : ServletRequest 에 보안 컨텍스트를 저장한다. 세션에 저장한 것이 아니므로 컨텍스트 영속성이 유지되지 않는다.
💡 ServletRequest는 매 요청마다 요청객체가 바뀌므로 영속성을 유지할 수 없다
-
NullSecurityContextRepository : 세션을 사용하지 않는 인증(JWT, OAuth2) 일 경우 사용하며 컨텍스트 관련 아무런 처리를 하지 않기 때문에 SecurityContextRepository의 도움을 받지 않는다
SecurityContextHolderFilter
- SecurityContextRepository 를 사용하여 SecurityContext를 얻고 이를 SecurityContextHolder 에 설정하는 필터 클래스
- SecurityContext를 세션에 저장하지 않는다
- 인증이 지속되어야 하는지를 각 인증 메커니즘이 독립적으로 선택할 수 있게 하여 더 나은 유연성을 제공하고 HttpSession 에 필요할 때만 저장함으로써 성능을 향상시킨다
SecurityContext 생성, 저장, 삭제
- 익명 사용자
- SecurityContextRepository 를 사용하여 새로운 SecurityContext 객체를 생성하여 SecurityContextHolder 에 저장 후 다음 필터로 전달
- Authentication이 null이므로 AnonymousAuthenticationFilter 에서 AnonymousAuthenticationToken 객체를 SecurityContext 에 저장
- 인증 요청
- SecurityContextRepository 를 사용하여 새로운 SecurityContext 객체를 생성하여 SecurityContextHolder 에 저장 후 다음 필터로 전달
- UsernamePasswordAuthenticationFilter 에서 인증 성공 후 인증상태를 유지하기 위해 SecurityContext 에 UsernamePasswordAuthentication 객체를 SecurityContext 에 저장
- SecurityContextRepository 를 사용하여 HttpSession 에 SecurityContext 를 저장(강제로 SecurityContextRepository.saveContext()를 실행)
- 인증 후 요청
- SecurityContextRepository 를 사용하여 HttpSession 에서 SecurityContext 꺼내어 SecurityContextHolder 에서 저장 후 다음 필터로 전달
- SecurityContext 안에 Authentication 객체가 존재하면 계속 인증을 유지한다
- 클라이언트 응답 시 공통
- SecurityContextHolder.clearContext() 로 컨텍스트를 삭제 한다 (스레드 풀의 스레드일 경우 반드시 필요)
💡 현재는 SecurityContextPersistFilter 대신 SecurityContextHolderFilter를 사용한다
💡 커스텀 한 인증 필터를 구현할 경우 인증이 완료된 후 SecurityContext를 SecurityContextHolder에 설정한 후 SecurityContextRepository에 저장하기 위한 코드를 작성해야 한다