TIL - 20250813

juni·2025년 8월 13일

TIL

목록 보기
93/317

0813 여행 생성 API 구현 및 JWT 인증 필터 적용


✅ 1. 여행 생성 API 구현 (Controller & Service)

  • 사용자가 새로운 여행 계획을 생성할 수 있는 백엔드 API(POST /api/trips)를 구현했습니다.
  1. TripRequest (DTO):
    • 클라이언트로부터 여행 생성에 필요한 데이터(제목, 설명, 기간, 예산 등)를 받기 위한 DTO를 정의했습니다.
    • @NotBlank, @NotNull 등 유효성 검증 어노테이션을 사용하여 API 요청 데이터의 무결성을 보장합니다.
  2. TripService (createTrip 메서드):
    • 컨트롤러로부터 받은 TripRequest와 사용자 정보를 바탕으로 Trip 엔터티를 생성하고, tripRepository.save()를 통해 데이터베이스에 저장하는 핵심 비즈니스 로직을 담당합니다.
    • 사용자 존재 여부를 검증하고, 없을 경우 BusinessException을 발생시켜 일관된 예외 처리를 따릅니다.
  3. TripController:
    • @PostMapping을 통해 API 엔드포인트를 매핑하고, @Valid로 DTO 유효성 검사를 수행합니다.
    • 인증된 사용자 정보는 @AuthenticationPrincipal을 통해 직접 받아 TripService에 전달합니다.

✅ 2. JWT 인증 필터 적용 및 Security 설정

  • 기존에 생성만 하던 JWT를 실제로 검증하고 인증을 처리하기 위해 JwtAuthenticationFilter를 도입하여 Spring Security 파이프라인에 통합했습니다. 이로써 완전한 Stateless 인증 시스템이 완성되었습니다.

➕ 인증 필터 처리 흐름

  1. 클라이언트가 API 요청 시 HTTP 헤더에 JWT(Authorization: Bearer ...)를 담아 보냅니다.
  2. JwtAuthenticationFilter가 요청을 가로채(Intercept) 헤더에서 토큰을 추출합니다.
  3. JwtProvider.validateToken()을 통해 토큰의 유효성(만료 여부, 서명 일치 등)을 검증합니다.
  4. 토큰이 유효하면, JwtProvider.getUsernameFromToken()으로 사용자 정보를 추출합니다.
  5. 추출된 사용자 정보로 UsernamePasswordAuthenticationToken 객체를 생성합니다.
  6. 생성된 Authentication 객체를 SecurityContextHolder에 저장합니다. 이 시점부터 해당 요청은 인증된 사용자의 요청으로 처리됩니다.

SecurityConfig 주요 변경 사항

  • 커스텀 필터 등록: addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) 코드를 통해 우리가 직접 만든 JwtAuthenticationFilter가 Spring Security의 기본 인증 필터보다 먼저 동작하도록 설정했습니다.
  • 접근 제어 (인가) 설정:
    • permitAll(): 로그인, 회원가입, 정적 리소스 등 인증 없이 접근 가능한 경로를 명시적으로 허용했습니다.
    • authenticated(): /api/** 등 나머지 모든 경로는 반드시 인증된 사용자만 접근할 수 있도록 설정하여 API를 보호합니다.

✅ 3. 인증된 사용자 정보 활용 (@AuthenticationPrincipal)

  • SecurityContextHolder에서 직접 사용자 정보를 꺼내는 번거로운 과정을 없애고, 컨트롤러 메서드에서 인증된 사용자 정보를 파라미터로 바로 주입받도록 개선했습니다.

  • 개선 전:

    // SecurityContextHolder.getContext().getAuthentication().getName(); 과 같은 복잡한 코드 필요
  • 개선 후 (TripController):

    @PostMapping
    public ApiResponse<Void> createTrip(
        @Valid @RequestBody TripRequest request,
        @AuthenticationPrincipal UserDetailsImpl userDetails // 바로 주입받아 사용
    ) {
        tripService.createTrip(request, userDetails.getUsername());
        return ApiResponse.ok("여행이 성공적으로 등록되었습니다.");
    }
    • @AuthenticationPrincipal 어노테이션을 통해 JwtAuthenticationFilterSecurityContextHolder에 저장한 사용자 정보를 간편하게 조회할 수 있어 코드의 가독성과 테스트 용이성이 크게 향상되었습니다.

✅ 4. 프론트엔드 연동: 여행 등록/관리 화면 구현

  • 백엔드에서 구현한 여행 생성 API를 실제로 사용할 수 있도록 프론트엔드에 여행 등록/수정 페이지(trip-form.html, trip-form.js)를 추가했습니다.

  • 주요 구현 내용:

    • DTO 추가: 여행 목록 조회 및 검색에 필요한 TripSearchRequestDto, TripListItemDto 등 UI 맞춤형 DTO를 추가했습니다.
    • UI 구현: 사용자가 여행 정보를 입력하고 '저장' 버튼을 누르면 api.js를 통해 백엔드에 POST 요청을 보내도록 trip-form.js를 구현했습니다.
    • 라우팅 추가: PageControllerroutes-config.js/trips/new, /trips/{tripId}/edit 등의 경로를 추가하여 새로운 페이지가 정상적으로 렌더링되도록 설정했습니다.
    • 목록 페이지 개선: trip-list.js에 상태별 필터링 기능을 추가하여 사용자가 원하는 여행만 필터링해서 볼 수 있도록 UI를 개선했습니다.

📌 요약

  • 여행 정보를 생성하는 핵심 백엔드 API(TripService, TripController)를 구현하고 DTO 유효성 검사를 적용했습니다.
  • 요청 헤더의 JWT를 검증하여 사용자를 인증하는 JwtAuthenticationFilter를 구현하고 SecurityConfig에 등록함으로써, 토큰 기반의 Stateless 인증 파이프라인을 완성했습니다.
  • @AuthenticationPrincipal을 활용하여 컨트롤러에서 인증된 사용자 정보를 간결하고 효율적으로 사용하도록 리팩토링했습니다.
  • 백엔드 API와 연동되는 프론트엔드 여행 등록/수정 페이지를 구현하고, 목록 페이지에 필터 기능을 추가하여 사용자 편의성을 높였습니다.

0개의 댓글