SecurityContextRepository
- 스프링 시큐리티에서 사용자가 인증 이후 요청에 대해 계속 사용자의 인증을 유지하기 위해 사용되는 클래스
- Repository ⇒ 인증 상태를 유지하기 위한 저장소
- 인증 상태의 영속 메커니즘
- 사용자가 인증 성공 시 해당 사용자의 인증 정보와 권한(인증 객체)이 SecurityContext에 저장
- HttpSession을 통해 요청 간 영속이 이루어 지는 방식
인증 요청
- 사용자 로그인 요청(아이디, 패스워드 입력)
- AuthenticationFilter가 해당 정보를 AuthenticationManager에게 전달하여 인증 객체를 AuthenticationFilter에 반환
- Authentication 객체를 SecurityContext에 저장
- SecurityContext를 명시적으로 저장소(SecurityContextRepository)에 보관
- HttpSession에 SecurityContext에 저장
인증 후 요청
- /user에 접근 요청
- SecurityContextHolderFilter가 컨텍스트 저장소로 부터 컨텍스트를 로드
- SecurityContextRepository를 사용하여 세션으로부터 컨텍스트 존재를 확인
- HttpSession에 저장된 컨텍스트를 로드
→ Authencation 객체가 null이라면 인증 X, null이 아니라면 인증 O
구조
메서드명 | 설명 |
containsContext | 현재 사용자를 위한 보안 컨텍스트가 저장소에 있는지 확인 |
saveContext | 인증 요청 완료 시 보안 컨텍스트를 저장 |
loadDeferredContext | 로딩을 지연시켜 필요 시점에 SecurityContext 로드 |
- HttpSessionSecurityContextRepository
- 요청 간에 HttpSession에 보안 컨텍스트를 저장
- 후속 요청 시 컨텍스트 영속성 유지
- RequestAttributeSecurityContextRepository
- ServletRequest에 보안 컨텍스트 저장
- 후속 요청 시 컨텍스트 영속성 유지 불가
- NullSecurityContextRepository
- 세션을 사용하지 않는 인증(JWT, OAuth2)일 경우 컨텍스트 관련 아무런 처리를 하지 않음
- DelegatingSecurityContextRepository
- RequestAttributeSecurityContextRepository와 HttpSessionSecurityContextRepository를 동시에 사용할 수 있도록 위임된 클래스
- 초기화 시 기본으로 설정
SecurityContextHolderFilter
- SecurityContextRepository를 사용하여 SecurityContext를 얻고 이를 SecurityContextHolder에 설정하는 필터 클래스
- 필터 클래스는 SecurityContextRepository.saveContext()를 강제로 실행시키지 않고 사용자가 명시적으로 호출되어야 SecurityContext를 저장 가능
→ SecurityContextPersistenceFilter와 다른 점 - 인증이 지속되어야 하는 지를 각 인증 메커니즘이 독립적으로 선택할 수 있게 하여 더 나은 유연성을 제공, HttpSession에 필요할 때만 저장함으로써 성능 향상
→ 과거에는 굳이 저장을 하지 않아도 되는 것조차 무조건 저장을 했었기에 다른 사이드 이펙트(?)가 발생했다고 함
→ 이러한 이유로 어떠한 경우는 저장, 어떠한 경우에는 저장하지 않게 선택할 수 있도록 SecurityContextHolderFilter 클래스가 등장한 것 같음
SecurityContext 생성, 저장, 삭제
- 익명 사용자
- SecurityContextRepository 사용 → 새로운 SecurityContext 객체를 생성 → SecurityContextHolder에 저장 → 다음 필터로 전달
- AnonymousAuthenticationFilter(다음 필터)에서 AnonymousAuthenticationToken 객체를 SecurityContext 에 저장
→ SecurityContext의 인증 객체는 null이 들어가 있어, 이걸 꺼내서 익명 인증 토근으로 SecurityContext에 다시 저장
- 인증 요청
- SecurityContextRepository 사용 → 새로운 SecurityContext 객체를 생성 → SecurityContextHolder에 저장 → 다음 필터로 전달
- UsernamePasswordAuthenticationFilter(다음 필터) 에서 인증 성공 후 UsernamePasswordAuthentication 객체를 SecurityContext 에 저장
- SecurityContextRepository 사용 → HttpSession에 SecurityContext 저장→ 커스텀 인증 필터를 만들고 사용할 때 Session에 SecurityContext를 저장하는 코드가 포함되지 않으면 강제적으로 세션에 저장하는 작업을 해주어야 함
→ 폼 인증을 위한 필터(UsernamePasswordAuthentication)에서는 강제적으로 SecurityContext를 세션에 저장하는 역할을 하여 인증을 유지해줌
- 인증 후 요청
- SecurityContextRepository 사용 → HttpSession에서 SecurityContext 꺼내어 SecurityContextHolder에서 저장 → 다음 필터로 전달
- SecurityContext 안에 Authentication 객체가 존재 시인증 유지
- 클라이언트 응답 시 공통
- SecurityContextHolder.clearContext() 로 컨텍스트를 삭제
→ 스레드 풀의 스레드일 경우 반드시 필요
- SecurityContextHolder.clearContext() 로 컨텍스트를 삭제
SecurityContextHolderFilter 흐름도
- 클라이언트 요청 수신
- SecurityContextHolderFilter 무조건 작동
- SecurityContextRepository에서 HttpSession을 확인
- SecurityContext에 존재하지 않음
- 새로운 SecurityContext 생성하여 SecurityContextHolder에 저장
- 현재 Authentication 상태는 null
- AuthenticationFilter가 인증 수행
- SecurityContext에 인증 객체(AuthenticationToken) 저장
- SecurityContextRepository를 통해 세션에 SecurityContext 저장
- Form 인증이라면 위의 과정을 거치지만, 커스텀 인증 필터는 4번의 과정이 없어 명시적으로 저장 수행 필요
- 새로운 SecurityContext 생성하여 SecurityContextHolder에 저장
- SecurityContext에 존재
- SecurityContext를 로드하여 SecuriyContextHolder에 저장하여 다음 필터로 전달
- 다음 필터로 전달하기 전 SecurityContextHolder안에 SecurityContext 삭제
- 다음 요청에서 SecurityContext안의 인증 객체가 null인 상태에서 시작해야하기 때문
SecurityContextHolderFilter & SecurityContextPersistanceFilter
- SecurityContextRepository를 사용하여 SecurityContext를 로드하는 것은 동일
- SecurityContextHolderFilter
- 응답 시점에 Session에 SecurityContext를 저장하지 않음
- SecurityContextPersistenceFilter
- 응답 시점에 Session에 SecutiryContext를 저장
securityContext() API
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity hhtp) throws Exception{
http.securityContext(securityContext -> securityContext
.requiredExplicitSave(true);
return http.build();
}
- requirceExplicitSave()
- SecurityContext를 명시적으로 저장할 것인지 아닌지 여부 설정(Default true)
- ture ⇒ SecurityContextHolderFilter 실행
- false ⇒ SecurityContextPersistenceFilter 실행
- SecurityContext를 명시적으로 저장할 것인지 아닌지 여부 설정(Default true)
- 현재 SecurityContextPersistenceFilter는 Deprecated되어 레거시 시스템 외에는 SecurityContextHolder 사용
CustomAuthenticationFilter & SecurityContextRepository
- 커스텀한 인증 필터를 구현할 경우 인증 완료 후 SecurityContext를 SecurityContextHolder에 설정한 후 SecurityContextRepository에 저장하기 위한 코드를 명시적으로 작성
securityContextHolderStrategy.setContext(context);
securityContextRepository.saveContext(context, request, response);
- securityContextRepository는 HttpSessionSecurityContextRespository 혹은 DelegatingSecurityContextRepository 사용
'Language > Spring Security' 카테고리의 다른 글
세션 고정 보호 - sessionManagement().sessionFixation() (0) | 2024.07.26 |
---|---|
동시 세션 제어 - sessionManagement().maximumSessions() (0) | 2024.07.26 |
사용자 상세 - UserDetails (0) | 2024.07.24 |
사용자 상세 서비스 - UserDetailsService (0) | 2024.07.24 |
인증 제공자 - AuthenticationProvider (0) | 2024.07.24 |