개발 공부 기록

[SpringBoot] Interceptor 적용하기 본문

Spring/Development Log

[SpringBoot] Interceptor 적용하기

나만없서고냥이 2023. 12. 19. 00:25

✔️ 인터셉터(Interceptor)란?

'가로챈다'라는 의미를 가진 인터셉터는 사용자의 요청을 가로채는 역할을 합니다. Spring 프레임워크에서 제공하는 기능 중 하나인 이 인터셉터는 Controller가 요청을 처리하기 전, 그리고 처리한 후에 추가적인 로직을 수행할 수 있도록 도와줍니다. 예를 들어 인터셉터가 요청에 대한 인증 및 권한 검사를 수행함으로써, 특정 요청이 처리되기 전에 사용자의 인증 상태를 확인할 수 있습니다.


✔️ 인터셉터 구현하기

HandlerInterceptor 인터페이스를 구현하며, 아래는 이 인터페이스를 구현하는데 사용될 수 있는 메서드입니다.

  • preHandle() : 컨트롤러(핸들러)가 실행되기 전에 호출됩니다. 이 메서드에서는 true를 반환하여 컨트롤러 실행을 계속하거나, false를 반환하여 요청을 중단시킬 수 있습니다.
  • postHandle() : 컨트롤러가 실행된 후, 뷰로  결과를 전달하기 전에 호출됩니다.
  • afterCompletion() : 뷰의 실행까지 완료된 후 호출됩니다. 이때 리소스 정리나 예외 처리 등의 작업을 할 수 있습니다.

1. MemberInterceptor.java

@Slf4j
@RequiredArgsConstructor
@Component
public class MemberInterceptor implements HandlerInterceptor {
    private final JwtTokenizer jwtTokenizer;
    private final MemberRepository memberRepository;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //log.info("Request URI : " + request.getRequestURI());
        String accessToken = jwtTokenizer.resolveToken(request);
        String email = jwtTokenizer.extractEmailFromToken(accessToken);

        validateUserExist(email);
        return true;
    }

    private void validateUserExist(String email) {
        if (isNotExistMember(email)) {
            throw new CustomException(CustomResponseCode.MEMBER_NOT_FOUND);
        }
    }

    private boolean isNotExistMember(String email) {
        return !memberRepository.existsByEmail(email);
    }
}

현재 사용자가 존재하는 사용자지 인증하는 부분입니다.

 

@Slf4j
@RequiredArgsConstructor
@Component
public class AdminInterceptor implements HandlerInterceptor {
    private final JwtTokenizer jwtTokenizer;
    private final MemberRepository memberRepository;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //log.info("Request URI : " + request.getRequestURI());
        String accessToken = jwtTokenizer.resolveToken(request);
        String email = jwtTokenizer.extractEmailFromToken(accessToken);

        Member member = findMember(email);
        if (hasNotRoleAdmin(member)) {
            throw new CustomException(CustomResponseCode.ACCESS_DENIED_EXCEPTION);
        }

        return true;
    }

    private boolean hasNotRoleAdmin(Member member) {
        return !member.hasRoleAdmin();
    }

    private Member findMember(String email) {
        return memberRepository.findByEmail(email).orElseThrow(() -> new CustomException(CustomResponseCode.MEMBER_NOT_FOUND));
    }

}

관리자만 접근할 수 있는 URI에 ADMIN이 아닌 MEMBER 권한을 가진 사용자가 접근했을 경우에 처리하는 부분입니다.


✔️ WebMvcConfig.java

@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
    private final MemberInterceptor memberInterceptor;
    private final AdminInterceptor adminInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(memberInterceptor)
                .order(1)
                .excludePathPatterns("/api/signup/**")
                .excludePathPatterns("/api/login")
                .addPathPatterns("/api/**");
        registry.addInterceptor(adminInterceptor)
                .order(2)
                .addPathPatterns("/api/admin/**");
    }
}

addInterceptors 메서드를 오버라이딩하여 InterceptorRegistry를 통해 애플리케이션 내에 인터셉터를 등록할 수 있습니다. excludePathPatterns()를 사용하여 메서드의 인자로 전달하는 URI와 경로를 인터셉터 호출에서 제외시킬 수 있습니다. 반면, addPathPatterns()를 사용하여 인터셉터를 호출하는 URI와 경로를 추가할 수 있습니다.