231016 TIL #217 횡단 관심사 / Filter

김춘복·2023년 10월 15일
0

TIL : Today I Learned

목록 보기
217/571

Today I Learned

오늘은 면접대비를 하면서 Spring의 주요기능인 AOP에 대해 공부하기 위해 우선 횡단관심사와 Filter에 대해 정리해보았다.


횡단 관심사


출처: 여름나라겨울이야기

개발을 하다보면 중복으로 발생하는 공통된 코드가 있다. 위의 그림처럼 로깅, 보안, 트랜잭션관리 등 다수의 모듈에서 반복적으로 나타나는 부분이 존재하는데 이를 횡단 관심사(Cross-cutting Concerns)라고 한다.

스프링에서는 이 횡단관심사를 처리할 수 있는 Filter, Interceptor, AOP가 존재한다. 이 기능들을 통해 횡단 관심사를 공통화해서 사용이 가능해지고, 중복코드를 줄여 유지보수를 쉽게 만든다.


출처 : sally의 프로그래밍 공부

하지만 Filter, Interceptor, AOP는 위의 그림처럼 적용되는 곳을 비롯해 차이점이 존재하는데, 각각의 상세한 기능에 대해 알아보려한다.


Filter

  • Filter는 Dispatcher Servlet(Request를 처리할 적절한 컨트롤러를 찾아 할당)에 Request가 전달 되기 전, 가장 먼저 수행되고 Spring Context 외부에 존재해 톰캣과 같은 웹 컨테이너(Servlet Container)에 의해 관리된다.

  • 일반적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업이 Filter에서 처리된다. 웹어플리케이션의 전체적인 흐름을 가로채 요청 or 응답을 수정하거나 추가 작업을 수행한다.

  • URL 패턴으로 대상을 구분해서 걸러낸다.

  • Filter에서는 Request와 Response를 조작할 수 있다.(아예 다른 객체로 변경 가능)

  • Interceptor, AOP와 다르게 스프링의 기능이 아니라 자바의 기능이다. 자바의 javax.servlet.Filter 인터페이스를 구현한다.

주 용도

  • 전역적인 보안 및 인증/인가 작업(XSS 방어)
  • 이미지/데이터 압축 및 문자열 인코딩 변환 처리
  • 모든 요청에 대한 로깅(Request가 왔는지 여부같은 큰 틀에서 로깅)
  • Spring과 분리되어야 하는 기능

Method

  • init()
    필터 객체를 초기화하고 서비스에 추가하기 위한 메서드. 웹 컨테이너가 init 메서드를 1번 호출해 필터 객체를 초기화하면 이후 요청들이 필터를 통해 처리된다.

  • doFilter()
    URL 패턴에 맞는 모든 HTTP 요청이 Dispatcher Servlet을 거치기 전/후에 이곳에서 처리된다.

  • destroy()
    필터 객체를 제거하고 자원을 반환한다.

Spring Security

Spring Security는 Filter를 기반으로 한 보안 프레임워크다. 개발자는 Spring Security를 사용하여 보안 필터 체인을 설정하고, URL 패턴에 따라 요청을 필터링하여 인증/인가를 구현할 수 있다. Spring Security는 다양한 기능과 확장성을 제공하며, 사용자 인증 및 인가, 세션 관리, 보안 헤더 설정, CSRF 방어, 로그인/로그아웃 처리 등 다양한 보안 작업을 처리할 수 있다.

구현 예시

  • Spring Security 환경에서 JWT 토큰을 통한 인증 절차를 Filter로 구현한 것이다. OncePerRequestFilter를 상속받아 모든 요청에서 한번만 작동한다. doFilterInternal 메서드를 override해서 인증절차를 구현하고, doFilter를 통해 다음 filterChain으로 요청을 넘긴다.
@RequiredArgsConstructor
@Slf4j
public class JwtAuthFilter extends OncePerRequestFilter {

  private final JwtUtil jwtUtil;
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {
    String token = jwtUtil.resolveToken(request);
    if (token != null) {
      if (!jwtUtil.validateToken(token)) {
        throw new CustomException(ExceptionType.TOKEN_VALIDATION_EXCEPTION);
      }
      Claims info = jwtUtil.getUserInfoFromToken(token);
      setAuthentication(info.getSubject());
    }
    filterChain.doFilter(request, response);
  }
  public void setAuthentication(String email) {
    SecurityContext context = SecurityContextHolder.createEmptyContext();
    Authentication authentication = jwtUtil.createAuthentication(email);
    context.setAuthentication(authentication);
    SecurityContextHolder.setContext(context);
  }

}
profile
Backend Dev / Data Engineer

0개의 댓글