서블릿 기반 애플리케이션일 경우, 엔드포인트에 요청이 도달하기 전에 중간에서 요청을 가로채 어떤 처리를 할 수 있는 포인트를 제공하는데 그것을 서블릿 필터 라고 한다.
- 서블릿 필터는 자바에서 제공하는 API
javax.servlet.Filter
인터페이스를 구현한 서블릿 필터는 웹 요청을 가로채어 전처리를 할 수 있으며, 엔드포인트에서 전달되는 응답을 클라이언트에게 전달 하기 전 후처리를 할 수 있다.
서블릿 필터는 하나 이상의 필터들을 연결하여 필터 체인을 구성할 수 있다.
디스패쳐서블릿에 클라이언트의 요청이 전달되기 전에 필터 체인을 구성한 예.
서블릿 필터는 각각의 필터들이 doFilter()
라는 메서드를 구현해야 하며, doFilter()
메서드 호출을 통해 필터 체인을 형성
보안
과 관련된 작업을 추가한다.DelegatingFilterProxy
와 FilterChainProxy
클래스는 Filter 인터페이스를 구현하므로 엄연한 서블릿 필터 역할을 한다. (조금 특별한 필터)⭐ DelegatingFilterProxy
- Spring Security 역시 Spring의 핵심인 ApplicationContext 를 이용한다.
- 서블릿 필터와 연결되는 Spring Security 만의 필터를 ApplicationContext에 Bean으로 등록한 후에 이 Bean들을 이용해서 보안과 관련된 여러가지 작업들을 처리하게 된다.
DelegatingFilterProxy
가 Bean으로 등록된 Spring Security의 필터를 사용하는 시작점이라고 생각하면 된다.- 서블릿 컨테이너 영역의 필터와 ApplicationContext에 Bean으로 등록된 필터들을 연결해주는 브릿지 역할을 한다.
FilterChainProxy
의 역할⭐ FilterChainProxy
- Spring Security의 필터를 사용하기 위한 진입점
- FilterChainProxy 부터 Spring Security에서 제공하는 보안 필터들이 필요한 작업을 수행한다.
- URL 별로 여러개 등록 가능, 필터 체인이 있을때 어떤 것을 사용할 지 FilterChainProxy가 결정하며 가장 먼저 매칭된 필터 체인을 실행한다.
ex)
/api/**
패턴의 Filter Chain이 있고,/api/message
URL 요청이 전송하는 경우
/api/**
패턴과 제일 먼저 매칭되므로 디폴트 패턴인/**
도 일치하나 가장 먼저 매칭되는/api/**
패턴과 일치하는 필터 체인만 실행한다./message/**
패턴의 필터 체인이 없는데/message/
URL 요청 전송하는 경우
- 매칭되는 필터 체인이 없으므로 디폴트 패턴인
/**
패턴의 필터 체인을 실행
(1) 사용자가 로그인 폼 등을 이용해 Username과 Password를 포함한 request를 Spring Security가 적용된 애플리케이션에 전송
사용자의 요청이 Filter Chain까지 들어오면 필터들 중에서 UsernamePasswordAuthenticationFilter
가 해당 요청 받는다.
요청을 전달 받은 필터는 Username과 Password를 이용해 (2)와 같이 UsernamePasswordAuthenticationToken
을 생성
Authentication
인터페이스를 구현한 구현 클래스이면 여기서 Authentication은 아직 인증이 되지 않음아직 인증되지 않은 Authentication
을 가지고 있는 UsernamePasswordAuthenticationFilter
는 (3)과 같이 해당 Authentication을 AuthenticationManager
에게 전달
AuthenticationManager
를 구현한 구현 클래스가 ProviderManager
이다.ProviderManager
가 인증이라는 작업을 총괄하는 실질적인 매니저(4) ProviderManager
로부터 Authentication을 전달 받은 AuthenticationProvider
는 (5)와 같이 UserDetailsService
를 이용해 UserDetails
를 조회
UserDetails
는 데이터베이스 등의 저장소에 저장된 사용자의 Username과 사용자의 자격을 증명해주는 크리덴셜인 Password, 사용자의 권한 정보를 포함하고 있는 컴포넌트UserDetails
를 제공하는 컴포넌트가 바로 UserDetailsService
이다.UserDetailsService
는 (5)에서 처럼 사용자의 크리덴셜을 초함한 사용자의 정보 조회
저장소에서 조회한 사용자의 크리덴셜을 포함한 사용자의 정보를 기반으로 (7)과 같이 UserDetails
를 생성한 후, 생성된 것을 다시 (8) AuthenticationProvider
에게 전달
UserDetails를 전달 받은 AuthenticationProvider
는 PasswordEncoder를 이용하여 UserDetails
에 포함된 암호화 된 Password와 인증을 위한 Authentication
안에 포함된 Password가 일치하는지 검증
AuthenticationProvider
는 인증된 Aithentication을 ProviderManager
에게 전달(10)
Authentication
은 인증을 위해 필요한 사용자의 로그인 정보를 가지지만,Authentication
은 인증에 성공한 사용자의 정보 (Principal, Credential, GrantedAuthorities)를 가지고 있다.ProviderManager
는 (11)과 같이 인증된 Authentication을 다시 UsernamePasswordAuthenticationFilter에게 전달한다.
(12)와 같이 SecurityContextHolder
를 이용해 SecurityContext
에 인증된 Authentication을 저장한다.
AuthorizationFilter
이다.AuthorizationFilter
는 (1) 과 같이 SecurityContextHolder로부터 Authentication을 획득AuthorizationManager
에게 전달한다.AuthorizationManager
는 권한 부여 처리를 총괄하는 매니저 역할을 하는 인터페이스RequestMatcherDelegationgAuthorizationManager
는 AuthorizationManager
를 구현하는 구현체 중 하나로 RequestMatcher 평가식을 기반으로 해당 평가식에 매치되는 AuthorizationManager
에게 권한 부여 처리를 위임하는 역할을 한다.RequestMatcherDelegationgAuthorizationManager
내부에서 매치되는 AuthorizationManager
구현 클래스가 있다면 해당 구현 클래스가 사용자의 권한을 체크 (3)AccessDeniedException
이 throw되고 ExceptionTranslationFilter가 예외를 처리하게 된다.