ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring 인터셉터를 활용한 User-Agent 기반 접근 제어
    카테고리 없음 2025. 2. 4. 15:01
    반응형

    Spring Interceptor로 특정 User-Agent 필터링 및 리디렉션하기

    • 핵심 키워드: Spring Interceptor, User-Agent 검사, Request Filtering, Access Control
    • 비슷한 개념: API Gateway에서 특정 User-Agent를 필터링하는 방식과 유사

    1. 들어가며


    웹 애플리케이션을 운영하다 보면 특정 클라이언트(User-Agent)만 접근을 허용하거나, 특정 User-Agent를 가진 요청을 별도의 페이지로 안내해야 하는 경우가 있습니다.

    예를 들면:
    ✅ 앱 전용 페이지를 제공하고 싶을 때
    ✅ 특정 User-Agent를 가진 봇이나 크롤러를 차단하고 싶을 때
    ✅ 웹과 앱에서 다른 화면을 보여주고 싶을 때

    이 글에서는 Spring MVC의 HandlerInterceptor를 활용하여 User-Agent를 검사하고, 특정 문자열이 없으면 다른 페이지로 리디렉트하는 방법을 소개하겠습니다.

    2. Spring Interceptor란?


    HandlerInterceptor는 Spring MVC에서 제공하는 인터페이스로, 컨트롤러가 실행되기 전에 요청을 가로채어 처리할 수 있는 기능을 제공합니다.

    주요 메서드는 다음과 같습니다:
    • preHandle(): 컨트롤러 실행 전에 요청을 가로채는 메서드
    • postHandle(): 컨트롤러 실행 후, 뷰 렌더링 전에 실행
    • afterCompletion(): 모든 요청 처리가 끝난 후 실행

    우리는 preHandle()을 활용하여 “User-Agent 헤더를 검사하고 특정 문자열이 없으면 리디렉트”하는 기능을 구현할 것입니다.

    3. User-Agent 검사 및 리디렉션 구현

    3.1 UserAgentInterceptor 만들기


    아래 코드처럼 HandlerInterceptor를 구현하여 특정 User-Agent를 체크하는 인터셉터를 만듭니다.

    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.HandlerInterceptor;

    public class UserAgentInterceptor implements HandlerInterceptor {

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // User-Agent 헤더 가져오기
            String userAgent = request.getHeader("User-Agent");

            // "LETTERAPP" 문자열이 포함되어 있는지 확인
            if (userAgent == null || !userAgent.contains("LETTERAPP")) {
                // 없으면 mainPage.do로 리디렉트
                response.sendRedirect("mainPage.do");
                return false; // 이후의 컨트롤러 처리를 중단
            }

            return true; // 정상적으로 진행
        }
    }

    3.2 Spring 설정 파일에 등록


    Spring MVC에서 인터셉터를 사용하려면 WebMvcConfigurer를 구현한 설정 클래스에서 등록해야 합니다.

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new UserAgentInterceptor())
                    .addPathPatterns("/**"); // 모든 요청에 대해 적용
        }
    }

    4. 실행 결과


    ✅ User-Agent에 “LETTERAPP”이 포함되어 있는 경우
    → 정상적으로 요청을 처리

    ✅ User-Agent에 “LETTERAPP”이 없는 경우
    → mainPage로 리디렉트

    5. 응용 및 확장


    이 방식을 활용하면 다양한 요구사항을 해결할 수 있습니다.

    ✔ 앱 전용 API 분리: 특정 User-Agent가 있는 경우 앱 API를, 없는 경우 웹 API를 호출하도록 설정 가능
    ✔ 크롤러 차단: User-Agent를 분석하여 검색 엔진 크롤러나 봇을 차단 가능
    ✔ 다중 User-Agent 지원: "LETTERAPP" 외에도 "MYAPP", "ANDROIDAPP" 등의 다양한 User-Agent를 허용 가능

    6. Spring Interceptor에서 예외 처리 추가하기


    기본적으로 response.sendRedirect("mainPage.do")를 사용하면 클라이언트가 직접 302 Redirect 응답을 받아 이동하지만, Spring의 예외 처리 방식을 활용하면 좀 더 깔끔하게 처리할 수 있습니다.

    여기서는 ModelAndViewDefiningException을 사용하여 리디렉션 대신 특정 뷰를 반환하도록 수정하겠습니다.

    🔹 수정된 UserAgentInterceptor

    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.ModelAndViewDefiningException;

    public class UserAgentInterceptor implements HandlerInterceptor {

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // User-Agent 헤더 가져오기
            String userAgent = request.getHeader("User-Agent");

            // "LETTERAPP" 문자열이 포함되어 있는지 확인
            if (userAgent == null || !userAgent.contains("LETTERAPP")) {
                // 리디렉트 대신 예외를 던져서 특정 뷰 반환
                ModelAndView mav = new ModelAndView("redirect:/mainPage.do");
                throw new ModelAndViewDefiningException(mav);
            }

            return true; // 정상 요청 처리
        }
    }

    🔹 ModelAndViewDefiningException을 사용하는 이유
    1. Spring MVC의 예외 처리 방식과 자연스럽게 통합
    • 예외가 발생하면 Spring의 예외 처리 메커니즘에 따라 에러 페이지가 아닌 특정 뷰를 반환할 수 있음.
    2. 리디렉트와 예외 처리를 깔끔하게 분리
    • sendRedirect()는 직접 응답을 조작하는 방식이라 예외 처리가 어렵지만, ModelAndViewDefiningException을 던지면 인터셉터 내부에서 요청 흐름을 자연스럽게 제어 가능.

    🔹 실행 흐름
    1. “LETTERAPP”이 포함된 요청 → 정상적으로 컨트롤러 실행
    2. “LETTERAPP”이 없는 요청 → "redirect:/mainPage.do"를 반환하여 자동 리디렉트
    3. 예외 발생 시
    • DispatcherServlet이 ModelAndViewDefiningException을 처리하여 지정된 뷰(mainPage.do)로 이동

    🔹 추가 응용 (커스텀 에러 페이지로 보내기)

    만약 mainPage.do가 아니라 에러 메시지가 포함된 별도 에러 페이지로 보내고 싶다면?

    if (userAgent == null || !userAgent.contains("LETTERAPP")) {
        ModelAndView mav = new ModelAndView("errorPage");  // errorPage.jsp or errorPage.html
        mav.addObject("message", "올바른 앱에서 접근해주세요."); // 에러 메시지 전달
        throw new ModelAndViewDefiningException(mav);
    }

    이렇게 하면 에러 메시지를 포함한 화면을 보여줄 수도 있습니다.


    ✅ sendRedirect() 대신 ModelAndViewDefiningException을 사용하면 Spring의 예외 처리 방식과 자연스럽게 연동 가능
    ✅ 특정 뷰로 리디렉트할 뿐만 아니라, 에러 메시지를 포함하는 것도 가능
    ✅ preHandle()에서 예외를 던지면 컨트롤러가 실행되지 않고 바로 뷰 렌더링이 가능

    이제 Spring Interceptor에서 더 깔끔하게 User-Agent를 검사하고 리디렉트할 수 있습니다!




    이번 글에서는 Spring Interceptor를 이용하여 User-Agent를 검사하고 특정 조건을 만족하지 않으면 리디렉트하는 방법을 살펴봤습니다.

    ✅ HandlerInterceptor를 사용하면 컨트롤러 실행 전에 요청을 제어할 수 있다.
    ✅ preHandle()에서 User-Agent 헤더를 확인하고 원하는 문자열이 없으면 리디렉트할 수 있다.
    ✅ WebMvcConfigurer를 활용해 인터셉터를 쉽게 적용할 수 있다.


    반응형
You can do everything.