본문 바로가기
개발진행목록/게시판 서비스

[JPA로 게시판 만들기] Spring Interceptor를 사용한 인증 체크

by o3oppp 2025. 3. 4.
스프링 인터셉터
  • 서블릿 필터와 같이 웹과 관련된 공통 관심 사항을 효과적으로 해결하는 기술
  • URL만 알면 로그인을 하지 않아도 여러 페이지에 접근이 가능하기 때문에, 이를 방지하기 위해 스프링 인터셉터를 사용
  • 자세한 내용은 여기에 게시하였습니다.

스프링 인터셉터 흐름과 제한

정상 요청

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러 // 정상 로그인 시

비적절한 요청

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 (이후 컨트롤러 호출X)

인터셉터 구현

LoginCheckInterceptor.java

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import project.post.session.SessionConst;

@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
    			  HttpServletResponse response,
                             Object handler) throws Exception {

        String requestURI = request.getRequestURI();
        log.info("인증 체크 인터셉터 실행 {}", requestURI);

        HttpSession session = request.getSession();

        if(session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null){
            log.info("미인증 사용자 요청");
            response.sendRedirect("login?redirectURL=" + requestURI);
            return false;
        }
        return true;
    }
}
  • HandlerInterceptor : 스프링 인터셉터를 사용하기 위해 해당 인터페이스를 구현
  • preHandle : 컨트롤러 호출 전 호출되는 Method
    • 응답값이 true이면 다음으로 진행하고, false이면 더 이상 진행하지 않음
  • response.sendRedirect : 정상 로그인 후 요청한 페이지로 리다이렉션을 위함

LoginController.java

@Controller
@RequiredArgsConstructor
public class LoginController {

    private final LoginService loginService;
    private final SessionManager sessionManager;

    @GetMapping("/login")
    public String loginForm(Model model){
        model.addAttribute("loginForm", new LoginForm());
        return "login/loginForm";
    }

    @PostMapping("/login")
    public String login(@Valid LoginForm loginForm, BindingResult result,
                        @RequestParam(defaultValue = "/") String redirectURL,
                        HttpServletRequest request){

        if(result.hasErrors()){
            return "login/loginForm";
        }

        Member loginMember = loginService.login(loginForm.getLoginEmail(), loginForm.getPassword());

        if(loginMember == null){
            result.reject("loginFail", "이메일 또는 비밀번호가 맞지 않습니다.");
            return "login/loginForm";
        }

        // 로그인 성공 처리
        // 세션이 있으면 세션 반환, 없으면 신규 세션 생성
        HttpSession session = request.getSession();
        session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
        return "redirect:" + redirectURL; // 요청 URL로 리다이렉션
    }
    ...
}
  • login Method 내 요청 URL로 리다이렉션을 위한 코드 추가

WebConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import project.post.interceptor.LogInterceptor;
import project.post.interceptor.LoginCheckInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginCheckInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/", "/login", "/logout", "/members/new", "/css/**", "/*.ico", "/error");
    }
}
  • WebMvcConfigurer가 제공하고는 addInterceptors()를 사용해서 인터셉터를 등록
  • registry.addInterceptor(new LoginCheckInterceptor()) : 인터셉터를 등록
  • order : 인터셉터의 호출 순서를 지정. 낮을수록 먼저 호출
  • addPathPatterns : 인터셉터를 적용할 URL 패턴을 지정
  • excludePathPatterns : 인터셉터에서 제외할 패턴을 지정

스프링 인터셉터 체인
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 인터셉터1 -> 인터셉터2 -> ... -> 컨트롤러
  • 스프링 인터셉터는 체인으로 구성되는데, 중간에 인터셉터를 자유롭게 추가 가능