inblog logo
|
DailyCoding
    Spring Boot

    12-4. (실습) 스프링 V3 (인증 - 필터, 인터셉터)

    박은서's avatar
    박은서
    Feb 24, 2026
    12-4. (실습) 스프링 V3 (인증 - 필터, 인터셉터)
    Contents
    1. 인증 (필터)※ 필터(Filter)1) LoginFilter.java2) FirstFilter.java3) FilterConfig.java4) FirstFilter.java - 브라우저에 출력5) FirstFilter.java - doFilter()6) LoginFilter.java7) FilterConfig.java2. 인증 (인터셉트)1) LoginInterceptor.java2) WebMvcConfig.java
    notion image

    1. 인증 (필터)

    ※ 필터(Filter)

    1) 필터(Filter)의 특징과 단점 정리

    ① 필터는 DispatcherServlet 앞에서 동작
    • Spring MVC 요청 흐름
      • Client → Filter → DispatcherServlet → Controller
        ➡️ 필터는 DispatcherServlet보다 먼저 실행됨
    ② 예외를 DispatcherServlet으로 넘길 수 없음
    • 필터에서 예외 발생 시
      • ❌ throw new Exception() → DispatcherServlet에서 캐치 불가
    • 이유
      • DispatcherServlet에 도달하기 전에 필터에서 이미 요청 처리됨
      • Spring의 @ControllerAdvice, @ExceptionHandler 적용 안 됨
    ③ 필터에서 예외 직접 처리 필요
    • 필터 내부에서 처리 방식
      • try-catch 사용
      • 직접 Response 작성
    • 예시 패턴
      • try { // 인증 체크 } catch (Exception e) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("Unauthorized"); return; }

    2) 필터에서 인증 처리 시 고려사항

    ① 인증 실패 시 DispatcherServlet 진입 차단이 정상
    • 핵심 개념
      • 인증/인가 실패 → 비즈니스 로직 진입 자체가 잘못
      • DispatcherServlet → Controller까지 갈 필요 없음
    ➡️ 필터에서 요청을 차단하는 것이 맞는 설계
    ② 필터는 "입구 차단기" 역할
    • 필터의 책임
      • 요청 전처리
      • 인증 / 인가 검사
      • 공통 보안 처리
    • DispatcherServlet의 책임
      • 핸들러 매핑
      • 컨트롤러 실행
      • 예외 처리

    3) 필터 vs 인터셉터 vs 컨트롤러 예외 처리

    구분
    필터
    인터셉터
    컨트롤러
    실행 위치
    DispatcherServlet 이전
    이후
    내부
    Spring 예외 처리 사용
    ❌ 불가
    ✅ 가능
    ✅ 가능
    주 용도
    인증 / 보안 / 인코딩
    권한 / 로깅
    비즈니스

    1) LoginFilter.java

    C:\workspace\spring_lab\boardv1\src\main\java\com\example\boardv1\_core\filter\LoginFilter.java
    package com.example.boardv1._core.filter; import java.io.IOException; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("----------------login filter----------------"); } }

    2) FirstFilter.java

    C:\workspace\spring_lab\boardv1\src\main\java\com\example\boardv1\_core\filter\FirstFilter.java
    package com.example.boardv1._core.filter; import java.io.IOException; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; public class FirstFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("----------------first filter----------------"); } }

    3) FilterConfig.java

    ① 코드

    C:\workspace\spring_lab\boardv1\src\main\java\com\example\boardv1\_core\filter\FilterConfig.java
    package com.example.boardv1._core.filter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<FirstFilter> firstFilter() { FilterRegistrationBean<FirstFilter> bean = new FilterRegistrationBean<>(); bean.setFilter(new FirstFilter()); bean.addUrlPatterns("/*"); // 모든 요청에 대해 검사 bean.setOrder(1); // 필터 순서 return bean; } @Bean public FilterRegistrationBean<LoginFilter> loginFilter() { FilterRegistrationBean<LoginFilter> bean = new FilterRegistrationBean<>(); bean.setFilter(new LoginFilter()); bean.addUrlPatterns("/*"); // 모든 요청에 대해 검사 bean.setOrder(2); // 필터 순서 return bean; } }

    ② 테스트

    notion image
    notion image

    4) FirstFilter.java - 브라우저에 출력

    ① 코드

    package com.example.boardv1._core.filter; import java.io.IOException; import java.io.PrintWriter; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; public class FirstFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("----------------first filter----------------"); PrintWriter pw = response.getWriter(); pw.println("block"); } }

    ② 테스트

    notion image

    5) FirstFilter.java - doFilter()

    ① 코드

    package com.example.boardv1._core.filter; import java.io.IOException; import java.io.PrintWriter; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; public class FirstFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("----------------first filter----------------"); // PrintWriter pw = response.getWriter(); // pw.println("block"); chain.doFilter(request, response); } }

    ② 테스트

    notion image

    6) LoginFilter.java

    package com.example.boardv1._core.filter; import java.io.IOException; import com.example.boardv1.user.User; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("------Login Filter-----------"); HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; HttpSession session = req.getSession(); User sessionUser = (User) session.getAttribute("sessionUser"); // 예외: GET /boards/{id} 상세보기는 인증 없이 허용 String uri = req.getRequestURI(); if ("GET".equals(req.getMethod()) && uri.matches(".*/boards/\\d+$")) { chain.doFilter(request, response); return; } // /boards/*, /replies/* 나머지 전부 인증 필요 if (sessionUser == null) { resp.sendRedirect("/login-form"); return; } chain.doFilter(request, response); } }

    7) FilterConfig.java

    ① 코드

    package com.example.boardv1._core.filter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<FirstFilter> firstFilter() { FilterRegistrationBean<FirstFilter> bean = new FilterRegistrationBean<>(); bean.setFilter(new FirstFilter()); bean.addUrlPatterns("/*"); // 모든 요청에 대해 검사 bean.setOrder(1); // 필터 순서 return bean; } @Bean public FilterRegistrationBean<LoginFilter> loginFilter() { FilterRegistrationBean<LoginFilter> bean = new FilterRegistrationBean<>(); bean.setFilter(new LoginFilter()); bean.addUrlPatterns("/boards/*"); bean.addUrlPatterns("/replies/*"); bean.setOrder(2); // 필터 순서 return bean; } }

    ② 테스트

    로그인하지 않고 update-form에 접근했을 때
    로그인하지 않고 update-form에 접근했을 때

    2. 인증 (인터셉트)

    1) LoginInterceptor.java

    C:\workspace\spring_lab\boardv1\src\main\java\com\example\boardv1\_core\interceptor\LoginInterceptor.java
    package com.example.boardv1._core.interceptor; import org.jspecify.annotations.Nullable; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.example.boardv1._core.errors.ex.Exception401; import com.example.boardv1.user.User; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; public class LoginInterceptor implements HandlerInterceptor { // 뷰가 완성되면 실행 -> 쓸 일이 거의 없음 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { System.out.println("------------------view render complete------------------"); } // 컨트롤러 메서드 호출 직전에 실행 (/boards, /replies) @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String uri = request.getRequestURI(); // localhost:8080/hello/5 -> /hello/5 // 예외: /boards/숫자 패턴 -> 인증 체크 안 함 if (uri.matches(".*/boards/\\d+$")) { return true; } HttpSession session = request.getSession(); User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { throw new Exception401("인증되지 않았습니다"); } return true; // 로그인 -> true -> 메서드 진입 / 로그인 X -> false -> 진입불가 } // 컨트롤러 메서드 호출 직후에 실행 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { System.out.println("------------------postHandle complete------------------"); } }

    2) WebMvcConfig.java

    C:\workspace\spring_lab\boardv1\src\main\java\com\example\boardv1\_core\interceptor\WebMvcConfig.java
    package com.example.boardv1._core.interceptor; 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 WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/boards/**") .addPathPatterns("/replies/**") .excludePathPatterns("/boards/[0-9]+"); } }
     
    Share article
    Contents
    1. 인증 (필터)※ 필터(Filter)1) LoginFilter.java2) FirstFilter.java3) FilterConfig.java4) FirstFilter.java - 브라우저에 출력5) FirstFilter.java - doFilter()6) LoginFilter.java7) FilterConfig.java2. 인증 (인터셉트)1) LoginInterceptor.java2) WebMvcConfig.java

    DailyCoding

    RSS·Powered by Inblog