📌 Spring Security
Spring Security
는 Servlet Filters
를 기반으로 동작한다.
Spring Security
는 인증, 권한 부여 및 보호를 제공하는 프레임워크이다.
전체적인 구조는 위와 같다.
Gradle 설정
plugins {
id 'io.spring.dependency-management' version "1.0.10.RELEASE"
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
}
📌 Filter
그래서 필터의 역할을 먼저 아는것이 중요한데,
Filter
영어 단어만 봐도 뭔가를 필터로 걸러주는 느낌이 난다.
업무중에 통신 하나하나의 로그를 다 찍는 과정을 Filter
를 통해서 구현했던 경험이 있다.
이 필터를 줄줄이 연결하면 FilterChain
이 되는 것이다.
다음은 스프링 공식문서에서 FilterChain
의 구조를 가져왔다.
구조
클라이언트는 서버에 요청을 보내고 컨테이너는 요청 URI
를 기반으로 HttpServletRequest
를 처리하는 필터와
필터체인을 생성한다. Spring MVC
에서의 Servlet
은 DispatcherServlet
이 된다.
Filter
인터페이스를 구현하면 doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
메소드를 구현해주어야 한다.
chain.doFilter()
를 호출하면 다음 필터를 차례대로 수행하는 것이다.
이렇게 필터들이 쭉 연결되어 기능을 수행한다고 생각하면 된다.
📌 DelegatingFilterProxy
구조
설명
Spring
은 Servlet 컨테이너
의 라이프사이클과
Spring
의 ApplicationContext
사이의 연결을 허용하는
DelegatingFilterProxy
라는 필터를 제공한다.
이 필터는 Servlet Filter
로 애플리케이션 컨텍스트에서 요청한 것을 스프링 컨테이너에 생성된
Bean Filter
를 찾고 그 필터를 호출한다.
DelegatingFilterProxy
는 컨테이너가 시작되기 전에 필터를 등록해야 하기 때문에 중요하다.
📌 FilterChainProxy
Spring Security
의 서블릿 지원은 FilterChainProxy
에 포함되어 있다.
FilterChainProxy
는 SecurityFilterChain
을 통해 여러 필터 인스턴스에 위임할 수 있도록
시큐리티에서 제공하는 특수 필터이다.
FilterChainProxy
는 Bean
이라서 DelegatingFilterProxy
안에 포함된다.
구조
이제보니 구조가 좀 잡혀가는것 같다.
클린코드와 자바의 정석을 읽었더니 시큐리티 아키텍처가 이해되는건 무엇일까.... 🤔🤔🤔
📌 SecurityFilterChain
SecurityFilterChain
은 클라이언트에서 필터를 돌다가 DelegatingFilterProxy
에 들어온 요청을
받아서 이 요청에 대해 처리해야 하는 Security Filter
를 찾아 수행한다.
구조
📌 Security Filter
핵심인 시큐리티 필터이다. 이 필터는 SecurityFilterChain API
를 사용해
FilterChainProxy
에 삽입된다. 이 필터들은 순서가 중요하다.
필터의 순서를 알 필요는 없다.
근데 알아두면 유용하게 사용할 수는 있다.
필터에는 다음과 같은 필터들이 존재하고 위에서 아래로 순서가 매겨져 있다.
- ChannelProcessingFilter
- WebAsyncManagerIntegrationFilter
- SecurityContextPersistenceFilter
- HeaderWriterFilter
- CorsFilter
- CsrfFilter
- LogoutFilter
- OAuth2AuthorizationRequestRedirectFilter
- Saml2WebSsoAuthenticationRequestFilter
- X509AuthenticationFilter
- AbstractPreAuthenticatedProcessingFilter
- CasAuthenticationFilter
- OAuth2LoginAuthenticationFilter
- Saml2WebSsoAuthenticationFilter
UsernamePasswordAuthenticationFilter
- OpenIDAuthenticationFilter
- DefaultLoginPageGeneratingFilter
- DefaultLogoutPageGeneratingFilter
- ConcurrentSessionFilter
DigestAuthenticationFilter
- BearerTokenAuthenticationFilter
BasicAuthenticationFilter
- RequestCacheAwareFilter
- SecurityContextHolderAwareRequestFilter
- JaasApiIntegrationFilter
- RememberMeAuthenticationFilter
- AnonymousAuthenticationFilter
- OAuth2AuthorizationCodeGrantFilter
- SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
- SwitchUserFilter
블럭이 쳐져있는 필터들을 유의해서 더욱 살펴봐야 하겠다.
📌 Handling Security Exceptions
위에서 ExceptionTranslationFilter
를 사용하면 AccessDeniedException
이나,
AuthenticationException
을 HTTP Response로 변환할 수 있다.
- 일단 들어온 요청에서
FilterChain.doFilter()
로 나머지 애플리케이션을 호출한다. - 사용자가 인증이 되지 않았거나,
AuthenticationException
이 발생한 경우에 인증을 진행한다.
이 경우 사용자가 성공적으로 인증되면RequestCache
에 사용자를 저장하고 이 캐시를 사용하여 원래 요청을 쭉 진행한다. - 여기서
AccessDeniedException
이 발생하게 되면 액세스는 거부되고,AccessDeniedHandler
는 이 예외를 처리하기 위해 호출된다.
이 설정이 AccessDeniedException
과 AuthenticationException
에 대한 예외처리가 없다면
ExceptionTranslationFilter
는 아무것도 수행하지 않는다.
정리
여기까지가 일단 스프링 시큐리티의 기본적인 흐름이다.
다음 포스팅에서는 인증(Authentication)
에 대해서만 쭉 다뤄보는것으로 하겠다.
어렴풋이 알고 있는 기본값들에 대해서만 사용할게 아니라 입맛에 따라 커스텀하며 필터를 작업해주는 것이
개발자의 역량이라고 생각한다. 이게 뒷받침되려면 당연히 이런 공식문서를 읽어보는게 답이다.
전체적인 아키텍처의 흐름을 알아야 잘 설계할 수 있다.
아무튼 이 아키텍처를 공부함으로써 어제의 나보다는 오늘이 더 성장했다.
업무나 프로젝트에 들어간 시큐리티에 대한 코드를 보면 지금보다 더 이해할거라고 자신한다 🔥🔥🔥🔥
'Spring > Security' 카테고리의 다른 글
로그인 동작 순서 (0) | 2022.08.09 |
---|---|
Authentication 인증 (0) | 2022.08.09 |