[Spring Security] Spring Security Basic - CustomFilter 추가하기

들어가며

SpringSecurity에서 Custom Filter를 추가하는 방법에 대해서 알아보자.

Custom Filter 추가하는 방법

addFilter

http.addFilter(new LoggingFilter());
  • 해당 기능은 SpringSecurity에 FilterComparator에 등록되어 있는 Filter들을 활성화 할때 사용 가능하다.
FilterComparator() {
  Step order = new Step(INITIAL_ORDER, ORDER_STEP);
  put(ChannelProcessingFilter.class, order.next());
  put(ConcurrentSessionFilter.class, order.next());
  put(WebAsyncManagerIntegrationFilter.class, order.next());
  put(SecurityContextPersistenceFilter.class, order.next());
  put(HeaderWriterFilter.class, order.next());
  put(CorsFilter.class, order.next());
  put(CsrfFilter.class, order.next());
  put(LogoutFilter.class, order.next());
  filterToOrder.put(
    "org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
			order.next());
  filterToOrder.put(
    "org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
			order.next());
  put(X509AuthenticationFilter.class, order.next());
  put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
  filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
			order.next());
  filterToOrder.put(
    "org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
			order.next());
  filterToOrder.put(
    "org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
			order.next());
  put(UsernamePasswordAuthenticationFilter.class, order.next());
  put(ConcurrentSessionFilter.class, order.next());
  filterToOrder.put(
    "org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
  put(DefaultLoginPageGeneratingFilter.class, order.next());
  put(DefaultLogoutPageGeneratingFilter.class, order.next());
  put(ConcurrentSessionFilter.class, order.next());
  put(DigestAuthenticationFilter.class, order.next());
  filterToOrder.put(
    "org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next());
  put(BasicAuthenticationFilter.class, order.next());
  put(RequestCacheAwareFilter.class, order.next());
  put(SecurityContextHolderAwareRequestFilter.class, order.next());
  put(JaasApiIntegrationFilter.class, order.next());
  put(RememberMeAuthenticationFilter.class, order.next());
  put(AnonymousAuthenticationFilter.class, order.next());
  filterToOrder.put(
    "org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
			order.next());
  put(SessionManagementFilter.class, order.next());
  put(ExceptionTranslationFilter.class, order.next());
  put(FilterSecurityInterceptor.class, order.next());
  put(SwitchUserFilter.class, order.next());
}
  • FilterComparator에 기본적으로 등록되어 있는 Filter order 참고
public HttpSecurity addFilter(Filter filter) {
  Class<? extends Filter> filterClass = filter.getClass();
  if (!comparator.isRegistered(filterClass)) {
    throw new IllegalArgumentException(
      "The Filter class "
	+ filterClass.getName()
	+ " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
  }
  this.filters.add(filter);
  return this;
}
  • 일반적으로 CustomFilter를 추가한다면 comparator에 등록이 되어 있지 않아 에러가 발생하게 되어 있다.
  • CustomFilter를 등록할 때는 addFilterBefore이나 addFilterAfter을 사용하라고 에러 메시지가 나온다.

addFilterBefore

public HttpSecurity addFilterBefore(Filter filter,
		Class<? extends Filter> beforeFilter) {
  comparator.registerBefore(filter.getClass(), beforeFilter);
  return addFilter(filter);
}

public void registerBefore(Class<? extends Filter> filter,
		Class<? extends Filter> beforeFilter) {
  Integer position = getOrder(beforeFilter);
  if (position == null) {
    throw new IllegalArgumentException(
      "Cannot register after unregistered Filter " + beforeFilter);
  }

  put(filter, position - 1);
}

private void put(Class<? extends Filter> filter, int position) {
  String className = filter.getName();
  filterToOrder.put(className, position);
}
  • 특정 Filter의 이전에 동작하게 Order를 설정을 할 수 있다.
http.addFilterBefore(new LoggingFilter(), WebAsyncManagerIntegrationFilter.class);
  • 해당 방식으로 등록을 하게 되면, WebAsyncManagerIntegrationFilter의 Order position에서 -1을 하여 LoggingFilter를 등록하게 된다.

addFilterAfter

public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
  comparator.registerAfter(filter.getClass(), afterFilter);
  return addFilter(filter);
}

public void registerAfter(Class<? extends Filter> filter,
		Class<? extends Filter> afterFilter) {
  Integer position = getOrder(afterFilter);
  if (position == null) {
    throw new IllegalArgumentException(
      "Cannot register after unregistered Filter " + afterFilter);
  }
  put(filter, position + 1);
}
  • 특정 Filter 이후에 동작하게 Order를 설정할 수 있다.
http.addFilterAfter(new LoggingFilter(), WebAsyncManagerIntegrationFilter.class);
  • 해당 방식으로 등록을 하게 되면, WebAsyncManagerIntegrationFilter의 Order position에서 +1을 하여 LoggingFilter를 등록하게 된다.

addFilterAt

public HttpSecurity addFilterAt(Filter filter, Class<? extends Filter> atFilter) {
  this.comparator.registerAt(filter.getClass(), atFilter);
  return addFilter(filter);
}
public void registerAt(Class<? extends Filter> filter,
		Class<? extends Filter> atFilter) {
  Integer position = getOrder(atFilter);
  if (position == null) {
    throw new IllegalArgumentException(
      "Cannot register after unregistered Filter " + atFilter);
  }

  put(filter, position);
}
  • 특정 Filter와 같은 Order로 CustomFilter를 등록 한다.
http.addFilterAt(new aLoggingFilter(), WebAsyncManagerIntegrationFilter.class);
  • 해당 방식으로 등록을 하게 되면, WebAsyncManagerIntegrationFilter의 Order position과 동일하게 LoggingFilter를 등록하게 된다.

마치며

  • Order에 대해서 설명이 없긴한데, Order는 숫자가 낮을수록 더 높은 우선순위를 가지고 있다.
  • addFilterBefore, addFilterAfter를 많이 사용하는데, addFilterAt의 경우는 Order가 같아서 같은 Order의 Filter에서 순서를 보장하기가 어려울 수 있다.

Leave a comment