본문 바로가기

Backend/Spring | SpringBoot

[Spring Security] Survlet 기반 Application 아키텍쳐(2)

반응형

이전글 : Survlet 기반 Application 아키텍쳐(1)

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  http
      .authorizeHttpRequests((authz) -> authz
          .anyRequest().permitAll()
      )
      .httpBasic(withDefaults());
  return http.build();
}

 

SecurityFilterChain를 사용하는 이유는 HttpSecurity를 통해 HTTP보안 설정 구성하기 위함이다.

보안 필터는 SecurityFilterChain API를 통해 FilterChainProxy에 삽입된다. 필터들은 인증, 권한 부여, 취약점 보호 등 다양한 목적으로 특정 순서대로 실행된다. 예를 들어 인증을 수행하는 필터가 권한 부여를 수행하는 필터보다 먼저 호출되도록 보장한다. 따라서 Spring Security의 필터 순서를 알고 고려할 필요는 없지만, 순서를 아는 것이 유익할 수 있다.
( cf.) : FilterOrderRegisteration Code )

 

FilterChain에 Custom Filter추가하기

1. 필터 생성하기

public class TenantFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
    						throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

		// request header로 부터 tenant id 가져오기
        String tenantId = request.getHeader("X-Tenant-Id");
        // tenant id로 접근 가능한지 구분
        boolean hasAccess = isUserAllowed(tenantId); 
        if (hasAccess) {
        	// 접근 가능하다면 doFilter수행
            filterChain.doFilter(request, response); 
            return;
        }
        // 접근 불가능 하다면 예외처리
        throw new AccessDeniedException("Access denied"); 
    }

}
tip . 한 요청에 1번만 동작한다면 Filter을 implemet하는 것 보다 OncePerRequestFilter를 상속받는 것이 낫다.

 

 

2. Security Filter Chain에 Filter추가하기

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        // ...
        // AuthorizationFilter가 동작이후에 TenantFilter가 동작하게 추가
        .addFilterBefore(new TenantFilter(), AuthorizationFilter.class); 
    return http.build();
}

 

Builder 종류

  • .addFilterBefore(A, B); // A필터 전에 B필터 추가
  • .addFilterAfter(A, B);  // A필터 후에 B필터 추가
  • .addFilterAt(A, B); // A필터가 B필터 동작 위치에서 동작

주의점 1)

필터 위치가 앞에 있으면 나중에 실행 = 추가는 앞(before)에 하는데 동작은 뒤에 한다.

 

주의점 2)

스프링 부트는 자동으로 내장 컨테이너에 필터를 등록할 수 있으며, 이로 인해 필터가 중복으로 호출될 수 있다. 중복 호출을 피하려면 FilterRegistrationBean을 선언하고 enabled 속성을 false로 설정하여 스프링 부트가 컨테이너에 필터를 등록하지 않도록 해야한다.

@Bean
public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilter filter) {
    FilterRegistrationBean<TenantFilter> registration = new FilterRegistrationBean<>(filter);
    registration.setEnabled(false);
    return registration;
}

 

반응형