개인 피드백/백엔드

세션 인터셉터 만들기

개발자의 첫 걸음 2025. 12. 24. 12:21
spring:
  # Mustache 템플릿 엔진 설정
  mustache:
    servlet:
      # 세션과 요청 속성을 템플릿에서 사용 가능하게 함
#      expose-session-attributes: true
#      expose-request-attributes: true

 

SessionInterceptor

package org.example.demo_ssr_v1_1._core.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.example.demo_ssr_v1_1.user.User;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 세션 정보를 뷰 모델에 주입하는 인터셉터
 * 모든 컨트롤러가 실행된 후 (postHandle), 공통적으로 뷰 에서
 * 로그인 사용자 정보를 쓸 수 있게 모델에 주입 시킴
 */
@Component
public class SessionInterceptor implements HandlerInterceptor {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 실제 뷰 렌더링 될 때만 로직을 실행 (안전성 보장)
        if(modelAndView != null) {

            // Tip. 성능 개선
            // true(기본값) 쓰면 로그인 안 한 방문자에게도 강제로 세션을 생성하며 메모리를 낭비함.
            // false 를 써서 **있으면 가져오고** 없으면 null 반환 하게 설정 함.
            HttpSession session = request.getSession(false);
            if(session != null) {
                User sessionUser = (User)session.getAttribute("sessionUser");
                // 머스태치 파일 렌더링 되기 전에 데이터를 중간에 개입해서 내려 줌.
                modelAndView.addObject("sessionUser", sessionUser);
            }
        }
    }
}

 

 

WebMvcConfig

package org.example.demo_ssr_v1_1._core.config;


import lombok.RequiredArgsConstructor;
import org.example.demo_ssr_v1_1._core.interceptor.LoginInterceptor;
import org.example.demo_ssr_v1_1._core.interceptor.SessionInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Spring MVC 설정 클래스
 * @C, @S, @R, @Com.., @Configuration
 */
// @Component 클래스 내부에서 @Bean 어노테이션을 사용해야 된다면 @Configuration 사용해야 한다.
@Configuration // 내부도 IoC 대상 여부 확인
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

    // DI 처리
    private final LoginInterceptor loginInterceptor;
    private final SessionInterceptor sessionInterceptor;

    // ps. 인터셉터는 당연히 여러개 등록 가능 함...
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(sessionInterceptor)
                        .addPathPatterns("/**");


        // 1. 설정에 LoginInterceptor 를 등록하는 코드
        // 2. 인터셉터가 동작할 URL 패턴 지정
        // 3. 어떤 URL 요청이 로그인 여부를 필요할지 확인 해야 함.
        //    /board/** <-- 일단 이 엔드포인트 다 검사 시킬 꺼야
        //    /user/**  <-- 일단 이 엔드포인트 다 검사 시킬 꺼야
        //    -> 단, 특정 URL 은 제외 시킬꺼야
        registry.addInterceptor(loginInterceptor)
                // /** <-- 모든 URL 제외 대상이 됨. 일단 사용 안함
                .addPathPatterns("/board/**", "/user/**", "/reply/**")
                .excludePathPatterns(
                        "/login",
                        "/join",
                        "/logout",
                        "/board/list",
                        "/",
                        "/board/{id:\\d+}",
                        "/css/**",
                        "/js/**",
                        "/images/**",
                        "/favicon.io",
                        "/h2-console/**"
                );
                // ||d+ 는 정규표현식으로 1개 이상의 숫자를 의미한다. 
                // /board/1, board/1234 <-- 허용 
                // /board/abc 같은 경우 매칭 되지 않음
    }
}