인터셉터 만들어 보기

 

목차

    💡 학습 목표
        1. 인터셉터의 개념을 활용해서 기능을 개발 할 수 있다.

    0. 사전 기반 지식

    인터셉터(Interceptor)는 스프링 MVC에서 제공하는 기능으로, 클라이언트의 요청을 처리하는 과정에서 특정 작업을 수행할 수 있도록 도와준다. 인터셉터는 컨트롤러의 메서드(URI)에 접근하는 과정에서 요청을 가로채어 전처리(pre-processing) 및 후처리(post-processing)를 할 수 있다.

     

    필터(Filter)와의 차이점

    • 필터는 서블릿 레벨에서 동작하며, 모든 요청에 대해 작동한다.
    • 인터셉터는 스프링 MVC 레벨에서 동작하며, 특정 핸들러(컨트롤러)로의 요청에만 작동한다.

    인터셉터를 통해 로그인 여부 확인, 권한 검사, 로깅, 요청 시간 측정 등 다양한 작업을 효율적으로 처리할 수 있다.

     

    1. 로그인 인터셉터 만들기

    로그인 인터셉터는 사용자의 로그인 상태를 확인하고, 로그인하지 않은 사용자가 보호된 리소스에 접근하려 할 때 적절한 조치를 취하는 역할을 한다.

    package com.tenco.blog_v2.common.config;
    
    import com.tenco.blog_v2.common.errors.Exception401;
    import com.tenco.blog_v2.user.User;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import jakarta.servlet.http.HttpSession;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    // IoC 를 안한 상태 이다. 
    public class LoginInterceptor implements HandlerInterceptor {
    
        /**
         * 컨트롤러 메서드 호출 전에 실행 되는 메서드 이다.
         * @param request current HTTP request
         * @param response current HTTP response
         * @param handler chosen handler to execute, for type and/or instance evaluation
         * @return
         * @throws Exception
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("LoginInterceptor preHandle 실행");
            // 로그인 여부 판단
            HttpSession session = request.getSession(false); // 기존 세션이 없다면 null 반환 한다.
            if(session == null) {
                throw new Exception401("로그인이 필요 합니다");
            }
    
            // 키 - 값  --> 세션 메모리지에 저장 방식은 map 구조 저장 (sessionUser) 문자열 사용 중
            User sessionUser =  (User) session.getAttribute("sessionUser");
            if(sessionUser == null) {
                throw new Exception401("로그인이 필요 합니다");
            }
            // return false <- 이면 컨트롤러로 들어가지 않는다.
            return true;
        }
    
        /**
         * 컨트롤러 실행 후, 뷰가 렌더링되기 전에 실행되는 메서드
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
        }
    
        /**
         * 뷰가 렌더링 된 후 실행되는 메서드
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
        }
    }

     

    2. 로그인 인터셉터 등록 하기

    작성한 인터셉터를 스프링 부트 애플리케이션에 등록하고, 적용할 URL 패턴을 설정한다.

    package com.tenco.blog_v2.common.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    // @Component  // IOC
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Autowired // DI 처리
        private LoginInterceptor loginInterceptor;
    
        /**
         * 인터셉터를 등록하고 적용할 URL 패턴을 설정하는 메서드이다.
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(loginInterceptor)
                    .addPathPatterns("/protected/**")  // 인터셉터를 적용할 경로 패턴 설정
                    .excludePathPatterns("/public/**", "/login", "/logout"); // 인터셉터를 제외할 경로 패턴 설정
        }
    }

    하지만 LoginInterceptor 아진 빈 등록 처리가 안되어 있다.

     

    LoginInterceptor 빈으로 등록 처리
    package com.tenco.blog_v2.common.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class InterceptorConfig {
    
        @Bean // 빈으로 등록 처리 : 로그인 인터셉터를 빈으로 등록
        public LoginInterceptor loginInterceptor() {
            return new LoginInterceptor();
        }
    
        // 
    
        //
    
        //
    
        //
    
    }
    • @Bean: 메서드가 반환하는 객체를 스프링의 빈으로 등록한다.
    • LoginInterceptor: 앞서 작성한 로그인 인터셉터를 빈으로 등록하여 WebConfig에서 주입받을 수 있게 한다.

    3. 어드민 기능 준비

    User 코드 추가 → private String role;
    // "USER", "ADMIN";
    @Column(nullable = false)
    private String role;

     

    샘플 데이터 수정
    -- 사용자 데이터 삽입
    INSERT INTO user_tb(username, password, email, role,  created_at) VALUES('길동', '1234', 'a@nate.com', 'USER', NOW());
    INSERT INTO user_tb(username, password, email, role, created_at) VALUES('둘리', '1234', 'b@nate.com', 'USER', NOW());
    INSERT INTO user_tb(username, password, email, role, created_at) VALUES('마이콜', '1234', 'c@nate.com', 'ADMIN', NOW());

     

    4. 인터셉터를 이용한 권한 관리

    인터셉터를 활용하여 특정 권한을 가진 사용자만 접근할 수 있도록 설정할 수 있다. 예를 들어, 관리자 권한을 가진 사용자만 접근할 수 있는 경로를 설정할 수 있다.

     

    AdminInterceptor
    package com.tenco.blog_v1.common.config;
    
    import com.tenco.blog_v1.common.errors.Exception403;
    import com.tenco.blog_v1.user.User;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import jakarta.servlet.http.HttpSession;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    public class AdminInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("AdminInterceptor preHandle 실행");
            HttpSession session = request.getSession(false);
    
            if (session == null) {
                throw new Exception403("접근이 금지되었습니다.");
            }
    
            User sessionUser = (User) session.getAttribute("sessionUser");
            if (sessionUser == null || sessionUser.getRole().equals("ADMIN")) {
                //if (sessionUser == null || ! sessionUser.isAdmin()) { // isAdmin() 메서드는 User 클래스에 구현되어 있다고 가정
                throw new Exception403("관리자 권한이 필요합니다.");
            }
    
            // 관리자 권한이 있는 경우 계속 진행
            return true;
        }
    
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                               ModelAndView modelAndView) throws Exception {
            System.out.println("AdminInterceptor postHandle 실행");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("AdminInterceptor afterCompletion 실행");
        }
    }

     

    InterceptorConfig 코드 추가
    @Bean
    public AdminInterceptor adminInterceptor() {
        return new AdminInterceptor();
    }

     

    WebConfig 코드 추가
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/protected/**")  // 인터셉터를 적용할 경로 패턴 설정
                .excludePathPatterns("/public/**", "/login", "/logout"); // 인터셉터를 제외할 경로 패턴 설정
        registry.addInterceptor(adminInterceptor)
                .addPathPatterns("/admin/**");
    }

    여러 개의 인터셉터가 적용될 때, 인터셉터의 실행 순서를 조정할 수 있다. 스프링은 인터셉터를 등록한 순서대로 실행한다.

    목차로 돌아가기

     

    'Spring Boot > Blog 프로젝트 만들기(JPA)' 카테고리의 다른 글

    JPARepository 란?  (0) 2024.10.14
    리팩토링  (2) 2024.10.14
    회원 정보 수정  (0) 2024.10.11
    에러 컨트롤러 및 커스텀 익셉션 만들기  (0) 2024.10.11
    에러 페이지 만들기  (1) 2024.10.11