Spring Boot 심화: CORS, 예외 처리, 인증 및 인터셉터

김채운·2026년 4월 8일

Spring Boot를 이용한 웹 애플리케이션 개발 시 보안과 유지보수성을 높이기 위한 심화 개념들을 정리한다. CORS 정책 대응부터 전역 예외 처리, 그리고 인터셉터를 이용한 인증 권한 관리까지의 내용을 포함한다.


1. CORS (Cross-Origin Resource Sharing)

CORS는 추가 HTTP 헤더를 사용하여, 한 출처(Origin)에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제다.

Origin의 정의

동일 출처(Same-Origin) 여부는 다음 세 가지 요소의 조합으로 결정된다.

  1. Protocol (http, https)

  2. Hostname (localhost, naver.com 등)

  3. Port (8080, 5173 등)

이 중 하나라도 다르면 Cross-Origin으로 간주되며, 브라우저의 기본 보안 정책인 SOP(Same-Origin Policy)에 의해 리소스 요청이 차단된다.

해결 방법

  • 개발용: Chrome 확장 프로그램('Allow CORS')을 사용하여 브라우저 수준에서 강제로 허용한다.

  • 서버 설정: @CrossOrigin 어노테이션을 사용하여 허용할 Origin을 명시한다.

컨트롤러나 메소드 단위로 지정 가능하며, @Configuration 클래스에서 전역 설정도 가능하다.


2. Exception Handling (예외 처리)

Spring Boot는 기본적으로 'WhiteLabel Error Page'를 제공하지만, 이는 서버의 내부 구조나 코드 위치를 노출할 위험이 있어 별도의 처리가 필수적이다.

1) View(JSP) 기반 예외 처리

@ControllerAdvice를 사용하여 전역에서 발생하는 예외를 가로채고 특정 에러 페이지로 유도한다.

@ControllerAdvice // 에러 처리를 전역으로 설정
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(RuntimeException.class) // 모든 RuntimeException 처리
    public ModelAndView handleRuntimeException(final RuntimeException e) {
        log.error("handleRuntimeException : {}", e.getMessage());
        ModelAndView mnv = new ModelAndView();

        if (e instanceof org.springframework.validation.BindException) {
            mnv.addObject("errmsg", "파라미터가 잘 전달되었는지 확인하세요.");
        } else if (e instanceof NoHandlerFoundException) {
            mnv.addObject("errmsg", "페이지를 찾을 수 없습니다.");
        } else {
            mnv.addObject("errmsg", "알 수 없는 오류가 발생하였습니다.");
        }
        
        mnv.setViewName("/error/commonerr"); // 에러 전용 뷰 경로
        return mnv;
    }
}

2) REST API(JSON) 기반 예외 처리

@RestControllerAdvice를 사용하면 객체를 반환할 시 자동으로 JSON으로 응답한다.

// 사용자 정의 예외 클래스
public class HelloException extends RuntimeException {
   private String code;
   public HelloException(String code, String msg) {
       super(msg);
       this.code = code;
   }
   public String getCode() { return code; }
}

@RestControllerAdvice
public class GlobalExceptionHandler2 {
    @ExceptionHandler(HelloException.class)
    public ErrorResponse handleHelloException(final HelloException e) {
        // JSON 형태로 에러 코드와 메시지 반환
        return new ErrorResponse(e.getCode(), e.getMessage());
    }
}

3. Login 및 상태 유지 기술

HTTP는 Stateless 프로토콜이므로 사용자의 상태를 유지하기 위해 별도의 기술이 필요하다.

방식특징
Cookie브라우저에 저장되는 텍스트 파일. 요청 시 자동으로 서버에 전송됨.
Session서버 메모리에 상태를 저장. 보안성이 좋으나 서버 부하가 발생할 수 있음.
JWTJSON 포맷의 토큰. 클라이언트가 헤더에 담아 전송하며, 서버는 상태를 저장하지 않음(Stateless).

Cookie를 이용한 로그인 구현 예시

@PostMapping("/login")
public String login(String userid, String userpwd, Model model, HttpServletResponse response) {
    MemberDto dto = service.login(userid, userpwd);
    if (dto != null) {
        Cookie cookie = new Cookie("ssafy_id", dto.getUserid());
        cookie.setMaxAge(60*60*24); // 24시간 유지
        cookie.setPath("/");
        response.addCookie(cookie); // 브라우저에 쿠키 전달
    } else {
        model.addAttribute("msg", "로그인 실패");
    }
    return "redirect:/";
}

4. Interceptor (인터셉터)

특정 요청을 처리하기 전후에 로직을 가로채어 실행한다. 로그인 여부 확인과 같은 공통 관심 사항(Cross-cutting Concerns)을 처리하기에 적합하다.

인터셉터 구현 및 등록

@Component
public class ConfirmInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Cookie[] cookies = request.getCookies();
        boolean isLogin = false;
        
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("ssafy_id".equals(cookie.getName())) {
                    isLogin = true;
                    break;
                }
            }
        }
        
        if (!isLogin) {
            response.sendRedirect("/"); // 로그인 안 되어있으면 홈으로
            return false; // 요청 진행 중단
        }
        return true; // 요청 진행 허용
    }
}

@Configuration
public class WebConfiguration implements WebMvcConfigurer {
    @Autowired
    private ConfirmInterceptor intercepter;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(intercepter)
                .addPathPatterns("/write", "/update/**", "/delete/**"); // 가로챌 경로 지정
    }
}

5. Swagger (API 문서화)

프론트엔드와 백엔드 간의 원활한 협업을 위해 REST API를 자동 문서화해주는 도구다. 의존성을 추가하고 설정 클래스를 작성하면 /swagger-ui/index.html 경로를 통해 API 명세서 확인 및 직접 테스트가 가능하다.

profile
개발 지식과 금융 트렌드를 포스팅하고 있습니다.

0개의 댓글