728x90
반응형

[Spring Security를 사용하기 위해 알아야하는 흐름]

 

스프링 Security는 Spring의 어떤 Layer에서 동작할까요?

해당 질문에 답하기 위해서는 필터와 인터셉터를 구분하고, 필터가 어떤 layer의 어떤 순서로 동작하는지 알고 있어야 합니다.

먼저, 스프링부트가 스프링에 비해 가지는 강점은 Tomcat(WAS 서버)가 내장되어 있기 때문에 WAS 서버를 별도로 설치할 필요가 없다는 것입니다.
(빌드의 결과물인 ~.jar 는 WAS 서버를 포함한 것이고, war 를 사용한다면 Tomcat서버를 따로 설치하여 실행해야 합니다.)

스프링부트가 WAS 서버까지 포함하고 있기 때문에 클라이언트의 Request가 왔을 때 어떤 순서로 서버가 해당 요청을 처리해주는지 흐름을 이해해야 합니다.

간략히 말하면, 클라이언트의 Request가 오면 서블릿 컨테이너를 거치고 스프링 컨테이너를 거치게 됩니다.

여기에 필터와 인터셉터를 덧붙여보면 클라이언트의 Request가 오면 서블릿 컨테이너를 거치고, 서블릿 필터를 거치고 스프링 컨테이너를 거치고 인터셉터를 거치게 됩니다.

여기에 Spring Security까지 더해보겠습니다.

이제는 클라이언트 Request가 오면 서블릿 컨테이너를 거치고 서블릿 필터를 거치고 Spring Security를 거치고 스프링 컨테이너를 거치고 그 다음 인터셉터가 동작하게 됩니다.

그럼 Spring Security는 서블릿 필터를 거친 뒤, DispatcherServlet에 가기전에 동작한다라고 볼 수 있습니다.

그런데 Spring Security는 아예 별개의 layer라기 보다는 Servlet Filter의 맨 끝에 붙어서 동작합니다.

즉, Servlet Filter가 실행된 뒤 Spring Security도 Servlet Filter처럼 동작합니다.

그럼 여기서 의문이 생기는 점은 Spring Security는 어떻게 서블릿 필터를 동작하게 할 수 있을까? 하는 점입니다.

왜냐하면 스프링 컨테이너는 스프링 빈만을 관리하고, 서블릿 필터는 서블릿 컨테이너가 관리합니다.
즉, 서블릿 필터는 스프링에서 정의된 Bean을 주입해서 사용할 수 없습니다.

그래서 스프링에서는 DelegatingFilterProxy 라는 클래스가 존재하고, 이 클래스가 서블릿 필터와 Spring Security 동작의 핵심입니다.

DelegatingFilterProxy

DelegatingFilterProxy는 스프링은 자체적으로 서블릿의 Bean을 관리할 수 없기 때문에 서블릿 필터를 호출할 수 있는 DelegatingFilterProxy 를 호출한다고 이해하면 됩니다.

서블릿 컨테이너는 서블릿과 필터를 관리하며, 서블릿과 필터의 라이프사이클을 관리합니다. 따라서 스프링이 서블릿 필터를 호출하려면 서블릿 컨테이너를 통해 이를 수행해야 한다. DelegatingFilterProxy는 이를 가능하게 해주는 역할을 합니다.

이름그대로 해석하면 Filter Proxy를 위임한다 즉 가짜 서블릿 필터를 스프링에게 위임한다(제가 이해한..) 는 뜻인 것 같습니다.

헷갈릴 수 있는 부분

그런데 만약 스프링에서 Servlet Filter의 기능을 동작하고 싶으면 Filter를 생성하여서 WebConfig에 FilterRegistrationBean 와 @WebFilter 를 사용하는 방법도 있는데, 이것과는 다른 것입니다.
이 방법은 스프링과 직접적인 관련이 없고, 서블릿 API를 사용하는 방식입니다.
(그리고 보통 스프링을 사용하면 서블릿 필터보다는 스프링 인터셉터를 사용하여 처리하는 것이 더 많은 옵션을 제공하여 장점을 가집니다.)

FilterRegistrationBean 을 사용하는 방법은 서블릿 필터 API를 사용하여 필터를 등록하는 방법이고 DelegatingFilterProxy 는 스프링 컨테이너의 관리를 받고, Spring Security와 같이 사용됩니다.

FilterChainProxy

FilterChainProxy는 서블릿 필터로 등록되어 있고, DelegatingFilterProxy의 핵심 클래스입니다.
DelegatingFilterProxy 로 부터 요청 위임을 받고 실제 보안 요소들을 처리하는 역할입니다.

FilterChainProxy는 스프링에 빈으로 등록되어 있지만, Spring Security에서 서블릿 필터 마지막에 붙어서 서블릿 필터처럼 동작할 수 있습니다.

그럼 FilterChainProxydoFilter() 를 실행하게 됩니다.

FilterChainProxy는 해당 요청을 처리할 SecurityFilterChain 을 찾습니다.

일치하는 SecurityFilterChain 의 Security Filter를 순서대로 거쳐서 인증 및 인가처리를 하게 됩니다.

여기서 Security Filter에 해당하는 다양한 Filter들이 있습니다.
필요한 Filter만 적용할 수 있으며, Filter들의 순서를 조정할 수 있습니다. 여기서 로그인, 회원가입, JWT 토큰 생성 등을 할 때 보았던 UsernamePasswordAuthenticationFilter 가 있는 것입니다.

Filter에는 다음과 같은 종류가 있습니다.

SecurityContextPersistenceFilter

SecurityContextRepository에서 SecurityContext를 가져와 유저의 Authentication에 접근할 수 있도록 하는 Filter

LogoutFilter

로그아웃 요청을 처리하는 Filter

UsernamePasswordAuthenticationFilter

ID와 PW를 사용하는 Form기반 유저 인증을 처리하는 Filter

DefaultLoginPageGeneratingFilter

커스텀 로그인 페이지를 지정하지 않았을 경우, 기본 로그인 페이지를 반환하는 Filter

AnonymousAuthenticationFilter

이 Filter가 호출되는 시점까지 사용자가 인증되지 않았다면, 익명 사용자 토큰을 반환하는 Filter

ExceptionTranslationFilter

Filter Chain 내에서 발생된 모든 예외를 처리하는 Filter

FilterSecurityInterceptor

권한 부여와 관련된 결정을 AccessDecisionManager에게 위임해 권한 부여 및 접근 제어를 처리하는 Filter

RequestCacheAwareFilter

로그인 성공 후, 이전 요청 정보를 재구성 하기위해 사용하는 Filter

SessionManagementFilter

로그인 이후 인증된 사용자인지 확인하거나, 설정된 세션의 메커니즘에 따라 작업을 수행하는 Filter

BasicAuthenticationFilter

HTTP 요청의 인증 헤더를 처리하여 결과를 SecurityContextHolder에 저장하는 Filter

RememberMeAuthenticationFilter

세션이 사라지거나 만료 되더라도 쿠키 또는 DB를 사용하여 저장된 토큰 기반으로 인증을 처리하는 Filter

용어 정리

  • Authentication : 해당 사용자가 본인인지 확인하는 절차 => 인증
  • Authorization : 특정 페이지나 자원에 접근 가능한지 결정하는 요소 => 인가
  • Principal : 인증 대상 => 아이디
  • Credential : 인증하기 위해 필요한 정보 => 비밀번호
  • details : 인증 부가 정보

정리

그러니까 원래 서블릿 컨테이너 -> 서블릿 필터 -> Spring Security -> 스프링 컨테이너 -> 인터셉터 .. 이런식으로 동작하게 되는데, Spring Bean 중에 FilterChainProxy는 Spring Security의 필터들을 서블릿 필터 끝단에 붙게 해서 서블릿 필터처럼 동작하게 한다는 것입니다.

FilterChainProxy도 서블릿 필터로 등록되어 있으며, 해당 필터의 doFilter() 메서드가 호출되면 스프링 시큐리티 필터 체인이 실행되는 것입니다.

따라서, 스프링 시큐리티는 서블릿 필터가 동작한 다음에 적용되며, 이를 가능하게 한 것이 FilterChainProxy라고 생각할 수 있습니다.

클라이언트가 Request를 보내게 되면 서블릿의 필터를 거친 뒤, DelegatingFilterProxy를 호출하게 됩니다.

DelegatingFilterProxy는 핵심 클래스인 FilterChainProxy를 호출하게 된다. FilterChainProxy는 스프링에 빈으로 등록되어 있지만, Spring Security에서 서블릿 필터 마지막에 붙어서 서블릿 필터처럼 동작할 수 있습니다.

그럼 FilterChainProxy는 doFilter() 를 실행하게 됩니다.

FilterChainProxy는 해당 요청을 처리할 SecurityFilterChain 을 찾습니다.

일치하는 SecurityFilterChain 의 Security Filter를 순서대로 거쳐서 인증 및 인가처리를 하게 됩니다.

728x90
반응형

+ Recent posts