
이 시리즈는 Spring Security에 대한 학습을 한 후 기록하는 시리즈입니다. 해당 시리즈는 Spring Security 5.7 버전이므로 현재 6.x 버전과 설정방법은 다르지만 개념적 이해는 같으므로 5.7로 진행했습니다.
springSecurityFilterChain의 이름으로 생성되는 필터 빈입니다DelegatingFilterProxy로부터 요청을 위임받고 실제 보안 처리를 합니다.

RequestMatcher 설정합니다http.antMatcher("/admin/**")FilterChainProxy가 각 필터들을 가지고 있습니다RequestMatcher와 매칭되는 필터가 작동하도록 합니다SecurityContext에 저장되어 전역적으로 참조가 가능합니다Authentication authentication = SecurityContextHolder.getContext().getAuthentication()User 객체를 저장
Authentication 객체가 저장되는 보관소로 필요시 언제든지 Authentication 객체를 꺼내어 쓸 수 있도록 제공되는 클래스입니다ThreadLocal에 저장되어 아무 곳에서나 참조가 가능하도록 설계되어 있습니다HttpSession에 저장되어 어플리케이션 전반에 걸쳐 전역적인 참조가 가능합니다SecurityContext 객체 저장 방식MODE_THREADLOCAL: 스레드당 SecurityContext 객체를 할당, 기본값MODE_INHERITABLETHREADLOCAL: 메인 스레드와 자식 스레드에 관하여 동일한 SecurityContext를 유지MODE_GLOBAL: 응용 프로그램에서 단 하나의 SecurityContext를 저장SecurityContextHolder.clearContext(): SecurityContext 기존 정보 초기화SecurityContext 객체를 생성하여 SecurityContextHolder에 저장합니다AnonymousAuthenticationFilter에서 AnonymousAuthenticationToken 객체를 SecurityContext에 저장합니다SecurityContext 객체를 생성하여 SecurityContextHolder에 저장합니다UsernamePasswordAuthenticationFilter에서 인증 성공 후 SecurityContext에 UsernamePasswordAuthentication 객체를 SecurityContext에 저장합니다Session에 SecurityContext를 저장합니다Session에서 SecurityContext를 꺼내어 SecurityContextHolder에서 저장합니다SecurityContext안에 Authentication 객체가 존재하면 계속 인증을 유지합니다SecurityContextHolder.clearContext()


AuthenticationProvider 목록 중에서 인증 처리 요건에 맞는 AuthenticationProvider를 찾아서 인증 처리를 위임합니다ProviderManager를 설정하여 AuthenticationProvider를 계속 탐색할 수 있습니다
AuthenticatonProvider는 인터페이스이고, 주로 어플리케이션에 맞게 커스텀하게 구현해서 사용하는 경우가 많습니다authenticate: 인증을 위해서 검증하는 메소드supports: 인증을 처리할 수 있는 기준이 되는지 확인하는 메소드
AuthenticationException을 발생시킵니다AccessDeniedException을 발생시킵니다AccessDecisionManager에게 위임합니다
Voter들을 가질 수 있으며, Voter들로부터 접근허용, 거부, 보류에 해당하는 각각의 값을 리턴받고 판단 및 결정을 합니다Voter 클래스 중 하나라도 접근 허가로 결론을 내면 접근 허가로 판단합니다allowIfEqualGrantedDeniedDecisions를 false로 설정하면 접근 거부로 결정됩니다Voter가 만장일치로 접근을 승인해야 하며 그렇지 않은 경우 접근을 거부합니다판단을 심사하는 위원의 역할을 수행합니다
Voter가 권한 부여 과정에서 판단하는 자료
Authentication: 인증 정보(user)FilterInvocation: 요청 정보(antMatcher("/user"))ConfigAttributes: 권한 정보(hasRole("USER"))결정 방식
ACCESS_GRANTED: 접근 허용(1)ACCESS_DENIED: 접근 거부(0)ACCESS_ABSTAIN: 접근 보류(-1)Voter가 해당 타입의 요청에 대해 결정을 내릴 수 없는 경우

Config에 설정한 내용을 토대로 사용할 HttpSecurity가 Filter들을 구성합니다(Security 초기화)WebSecurity가 HttpSecurity가 설정한 filter들의 정보를 전달받은 후 FilterChainProxy의 빈 객체(springSecurityFilterChain)를 생성할 때, 해당 filter들을 인자로 넘겨서 생성합니다DelegatingFilterProxy는 특정 이름(springSecurityFilterChain)의 빈을 찾게 됩니다. DelegatingFilterProxy는 사용자의 요청을 찾은 springSecurityFilterChain에 위임합니다DelegatingFilterProxy가 사용자의 인증 요청을 받고, FilterChainProxy에 위임합니다FilterChainProxy는 이미 초기화 과정에서 관련 filter들의 목록을 가지고 있는 상태이므로, 위임을 받으면 해당 필터들을 순서대로 호출합니다.SecurityContextPersistenceFilter가 사용자의 요청을 받고, 내부에 있는 HttpSessionSecurityContextRepository가 로직을 수행합니다. 우선 loadContext를 실행해서 이전에 생성된 context가 있는지 확인해 보고 없다면 새로운 context를 생성하고, 다음 필터로 넘어갑니다 LogoutFilter는 로그아웃 요청이 없다면 특별히 기능을 수행하지 않고 다음 필터로 넘어갑니다UsernamePasswordAuthenticationFitler) 인증 객체에 사용자에게 입력받은 정보를 넣어 인증 객체(Authentication)를 생성한 후 AuthenticationManager에게 인증을 요청합니다. AuthenticationManager는 AuthenticationProvider에게 실질적으로 인증 로직을 수행하도록 합니다. AuthenticationProvider는 UserDetailsService를 통해서 해당 정보의 유효를 검사한 후에 인증된 정보일 경우 SecurityContextHolder의 SecurityContext안에 인증된 정보를 가진 Authentication 객체를 저장합니다.SessionManagementFilter의 내용 또한 수행하는데, ConcurrentSession을 확인해서 세션 최대 허용 개수를 초과하는 경우 두 전략 중 하나를 선택합니다SessionAuthenticationExceptionsession.expireNoeSessionFixation에서 세션 고정 보호를 위해서 새롭게 인증된 사용자에게 새로운 쿠키를 발급합니다. 마지막으로 Register SessionInfo 해당 사용자의 정보가 세션에 등록됩니다.SecurityContextPersistenceFilter의 HttpSessionSecurityContextRepository가 최종 인증된 사용자의 정보를 가지고 있는 SecurityContext 정보를 Session에 저장하고, 해당 SecurityContext는 삭제합니다DelegatingFilterProxy가 사용자의 인증 요청을 받고, FilterChainProxy에 위임합니다FilterChainProxy는 관련 filter들의 목록을 가지고 있는 상태이므로, 위임을 받으면 해당 필터들을 순서대로 호출합니다.SecurityContextPersistenceFilter는 HttpSessionSecurityContextRepository가 로직을 수행하도록 하고, HttpSessionSecurityContextRepository는 loadContext를 실행합니다. 이전 인증으로 Session에 저장된 SecurityContext가 존재하므로, context를 새로 생성하지 않고, 다음 필터로 넘어갑니다.LogoutFilter와 인증 필터는 지나갑니다(인가 처리이므로)ConcurrentSessionFilter 또한 동시적인 세션을 처리하기 위한 필터이고, 현재는 동시적인 세션 검증을 통과한 인증된 사용자이므로 지나갑니다.RememberMeAuthenticationFilter는 현재 사용자의 Session이 만료되거나 유실되어서, SecurityContext안의 Authentication 객체의 값이 null인 상태로, header에 remember-me라는 값을 가지고 있을 때 작동하는 필터이므로 지나갑니다AnonymousAuthenticationFilter는 현재 사용자가 인증을 시도하지 않고, 어떠한 권한도 없는 상태에서 바로 자원을 요청하는 경우에 동작하는 필터이므로 지나갑니다SessionManagementFilter는 현재 요청의 Session에 SecurityContext가 없거나 null일 경우 동작하는 필터이므로 마찬가지로 지나갑니다ExceptionTranslationFilter는 인증, 인가의 예외 처리를 하는 필터이므로, doFilter 메소드를 try-catch문으로 감싼 후 다음 필터로 이동합니다.FilterSecurityInterceptor는 현재 요청에서 두 가지를 확인합니다.AuthenticationException을 발생시킵니다.(예외는 이전 ExceptionTranslationFilter에서 처리합니다)AccessDecisionManager가 AccessDecisionVoter의 승인, 거부 결과가 거부라면 AccessDeniedException을 발생시킵니다.