모르지 않다는 것은 아는것과 다르다.

Spring Security

SecurityContextHolder 와 FilterChainProxy

채마스 2022. 2. 28. 20:26

FilterChainProxy

  • springSecurityFilterChain 의 이름으로 생성되는 필터 빈이며, Security Filter 들을 관리하는 빈이다.
  • DelegatingFilterProxy 으로 부터 요청을 위임 받고 실제 보안 처리한다.
  • 스프링 시큐리티 초기화 시 생성되는 필터들을 관리하고 제어한다.
  • FilterChainProxy는 요청에 따라 적합한 SecurityFilterChain 을 사용한다.
  • 기본 전략으로 DefaultSecurityFilterChain을 사용한다. -> DefaultSecurityFilterChain 는 Filter 리스트를 가지고 있다.
  • 사용자의 요청을 필터 순서대로 호출하여 전달한다.
  • 사용자정의 필터를 생성해서 기존의 필터 전.후로 추가 가능하다.
  • 아래에서 설정한 SecurityConfig 에서 설정한 값에 따라서 SecurityFilterChain 가 만들어지고, 만들어진 Chain 에 따라서 Filter 리스트가 다르다.
@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
        http.authorizeRequests() 
            .mvcMatchers("/", "/info").permitAll() 
            .mvcMatchers("/admin").hasRole("ADMIN") 
            .anyRequest().authenticated(); 

        http.formLogin(); 
        http.httpBasic(); 
    } 
}
  • SecurityFilterChain 를 여러개 만들고 싶으면 SecurityConfig를 여러개 만들어주면 된다.
    • 우선순위를 정해주고 싶으면 @Order 애노테이션을 사용할 수 있다.
    • 우선순위를 지정해 줄때 포괄적인 설정을 먼저 두면, 상세한 설정이 먹히기 때문에 주의해야한다.
      • "/**" 를 "/admin" 보다 먼저 두면 안된다.
  • SecurityConfig 인 구조는 아래와 같다.

  • 위와 같이 SecurityConfig 별로 만들어진 Filter 리스트 들은 securityFilterChains 에 담긴다.
  • FilterChainProxy 는 Filter 리스트에서 필터를 호출하는데, 필터의 종류는 아래와 같다. -> 설정에 따라 달라질 수 있다.
      1.  WebAsyncManagerIntergrationFilter
      2.  SecurityContextPersistenceFilter
      3.  HeaderWriterFilter
      4.  CsrfFilter
      5.  LogoutFilter
      6.  UsernamePasswordAuthenticationFilter
      7.  DefaultLoginPageGeneratingFilter
      8.  DefaultLogoutPageGeneratingFilter
      9.  BasicAuthenticationFilter
      10. RequestCacheAwareFilter
      11. SecurityContextHolderAwareReqeustFilter
      12. AnonymouseAuthenticationFilter
      13. SessionManagementFilter
      14. ExeptionTranslationFilter
      15. FilterSecurityInterceptor
  • 위의 필터중 SecurityContextPersistenceFilter, UsernamePasswordAuthenticationFilter 는 Authentication 객체를 관리한다.
  • UsernamePasswordAuthenticationFilter
    • 폼 인증을 처리하는 시큐리티 필터다.
    • 인증된 Authentication 객체를 SecurityContextHolder에 넣어주는 필터다.
  • SecurityContextPersistenceFilter
    • SecurityContext를 HTTP session에 캐시(기본 전략)하여 여러 요청에서 Authentication을 공유하는 필터다.
    • SecurityContextRepository를 교체하여 세션을 HTTP session 이 아닌 다른 곳에 저장하는 것도 가능하다.
    • 만약 SecurityContextPersistenceFilter 를 사용하지 않는다면? -> UsernamePasswordAuthenticationFilter 혹은 다른 필터를 사용해서 매 요청시 인증을 처리해야하고, 그 내용을 http 헤더나 본문에 포함해야 한다.
  • 만약 인증이 필요한 페이지에서 새로고침을 한다면? -> SecurityContextFilter 가 Security Context 를 꺼내준다. -> Http 세션이 달라지면 꺼내 올 수 없다.





DelegatingFilterProxy

  • 일반적인 서블릿 필터중 하나이다.
  • 서블릿 필터 처리를 스프링에 들어있는 빈으로 위임하고 싶을 때 사용하는 서블릿 필터이다.
  • 그럼 DelegatingFilterProxy 가 필요한 이유는 무엇일까?

  • 서블릿 필터는 스프링에서 정의된 빈을 주입해서 사용할 수 없다.
  • 특정한 이름을 가진 스프링 빈을 찾아서 그 빈에게 요청을 위임 해야한다.
  • DelegatingFilterProxy 는 타겟 빈 이름을 설정하는데, 아래와 같이 FilterChainProxy는 springSecurityFilterChain 이름으로, 빈으로 등록된다.
    public abstract class AbstractSecurityWebApplicationInitializer implements WebApplicationInitializer { 
        private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT."; 
        public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain"; 
        ... 
    }
  • 스프링 부트를 사용할 때는 자동으로 등록된다. (SecurityFilterAutoConfiguration)
  • 스프링 부트 없이 스프링 시큐리티 설정할 때는 AbstractSecurityWebApplicationInitializer를 사용해서 등록해야 한다.
  • 따라서 springSecurityFilterChain 이름으로 생성된 빈을 ApplicationContext 에서 찾아 요청을 위임한다.




REFERENCES

  • 백기선님의 스프링 시큐리티
  • 정수원님의 스프링 시큐리티