← 글 목록

Flyway 도입 시점과 DB 스키마 관리 전략, 그리고 스프링 인증 어노테이션 활용법

/ 10분 분량

이번 학습에서는 Flyway를 활용한 DB 스키마 관리 전략과 스프링 시큐리티의 인증 어노테이션을 효과적으로 사용하는 방법에 대해 깊이 있게 다루었습니다. 특히, 개발 초기 단계부터 DB 스키마 변경에 대한 효율적인 관리 방안과, API 개발 시 필수적인 인증 및 인가 처리에 대한 명확한 이해를 얻을 수 있었습니다.

Flyway 도입 시점과 DB 스키마 관리 전략, 그리고 스프링 인증 어노테이션 활용법

이번 학습에서는 Flyway를 활용한 DB 스키마 관리 전략과 스프링 시큐리티의 인증 어노테이션을 효과적으로 사용하는 방법에 대해 깊이 있게 다루었습니다. 특히, 개발 초기 단계부터 DB 스키마 변경에 대한 효율적인 관리 방안과, API 개발 시 필수적인 인증 및 인가 처리에 대한 명확한 이해를 얻을 수 있었습니다.

학습 주제

  • 공부 주제: Flyway 도입 시점 및 DB 스키마 관리 전략, 스프링 시큐리티 인증 어노테이션 활용
  • 대화 제목: Flyway 도입 시점과 DB 스키마 관리 전략 그리고 스프링의 인증 어노테이션
  • 학습 날짜: 2026년 4월 10일

질문과 탐구

이번 학습의 주요 질문은 다음과 같았습니다.

  1. Flyway 도입 시점: 프로젝트 초반의 잦은 스키마 변경으로 인한 개발 속도 저하 우려를 고려하여, Flyway 도입 시점과 베이스라인 설정 전략은 무엇인가?
  2. JPA vs. SQL 직접 관리: Flyway 도입 후 JPA와 SQL 직접 관리의 역할 분담은 어떻게 이루어져야 하는가? ddl-auto: validate 사용 시 주의사항은 무엇인가?
  3. Zero-Downtime Migration: 서버를 중단하지 않고 DB를 수정하는 Zero-Downtime Migration 전략의 핵심 요약과 적용 방법은?
  4. 스프링 인증 설계: BCrypt를 사용한 비밀번호 저장 및 검증, SecurityContext 활용, JWT sub 값 선택, ID 타입 통일 등 스프링 시큐리티 기반 인증 설계의 구체적인 적용 방안은?
  5. 블로그 모듈에서의 인증 활용: Flyway와 인증 설계에 대한 이해를 바탕으로, 자신이 담당하는 블로그 모듈에서 DB 변경 및 API 인증 처리를 어떻게 해야 하는가?
  6. @AuthenticationPrincipal 및 @PreAuthorize 동작 원리: 이 어노테이션들이 실제 어떻게 동작하며, API 개발 시 어떻게 활용해야 하는가?

이 질문들을 중심으로 ChatGPT와의 대화를 통해 DB 스키마 관리 및 스프링 시큐리티의 복잡한 개념들을 명확하게 파악하고, 실제 개발에 적용할 수 있는 구체적인 방안들을 탐구했습니다.

핵심 학습 내용

Flyway 도입 시점과 DB 스키마 관리 전략

  • 도입 시점: 스키마 변경이 잦은 프로젝트 초기에는 Flyway 도입을 보류하고, 테이블 구조가 어느 정도 안정화된 후에 도입하는 것이 효율적입니다.
  • 베이스라인 설정: 프로젝트 전체 DB 구조를 담은 SQL 파일을 베이스라인으로 설정하고, ddl-auto: validate 옵션을 사용하여 JPA가 테이블 구조 변경을 시도하는 것을 막고, 오직 엔티티와 DB 스키마 간의 일치 여부만 검증하도록 합니다.
  • Zero-Downtime Migration:
    • 새 컬럼 추가: nullable 옵션으로 추가하여 기존 코드가 터지지 않도록 합니다.
    • 컬럼 이름 변경: 새 컬럼을 추가하고, 기존 컬럼은 나중에 삭제하는 방식으로 진행합니다.
    • 컬럼 삭제: 코드에서 해당 컬럼을 사용하지 않도록 먼저 수정한 후, 그 다음에 SQL로 삭제합니다.
  • 역할 분리:
    • DDL (Data Definition Language): 테이블 구조 정의 및 변경은 Flyway SQL 파일이 담당합니다.
    • DML (Data Manipulation Language): 테이블 내 데이터의 조회, 삽입, 수정, 삭제는 JPA와 엔티티가 담당합니다.

스프링 시큐리티 인증 설계 및 활용

  • BCrypt: 비밀번호는 평문 저장이 아닌 BCrypt 해시로 저장하고, 로그인 시에는 저장된 해시와 사용자가 입력한 평문 비밀번호를 BCrypt.matches()를 통해 검증합니다. HTTPS 사용 및 접근 통제도 필수입니다.
  • SecurityContext: 요청 처리 동안 인증 정보를 SecurityContextHolder에 보관하며, 요청이 끝나면 해당 SecurityContext는 정리됩니다. 이는 ThreadLocal 기반으로 동작하여 스레드 간 인증 정보 충돌을 방지합니다.
  • JWT sub (Subject): JWT sub에는 변경 가능성이 적은 userId (UUID)를 사용하는 것이 좋으며, 이메일이 필요한 경우 userId로 DB 조회하는 방식을 사용합니다.
  • ID 타입 통일: member 테이블의 id가 UUID인 경우, FK로 연결되는 다른 테이블들도 UUID를 사용하여 ID 타입을 통일해야 합니다.
  • @AuthenticationPrincipal: SecurityContext에 저장된 인증 정보(Principal)를 컨트롤러 메서드의 파라미터로 쉽게 주입받을 때 사용합니다. CustomUserDetails와 같은 사용자 정의 객체를 통해 userId 등의 정보를 꺼내 사용할 수 있습니다.
    @GetMapping("/posts/my")
    public List<PostResponse> getMyPosts(@AuthenticationPrincipal CustomUserDetails user) {
        return postService.getMyPosts(user.getUserId());
    }
    
  • @PreAuthorize: 메서드 실행 전에 권한 체크를 수행하는 AOP 기반 어노테이션입니다.
    • @PreAuthorize("isAuthenticated()"): 로그인 사용자만 접근 가능하도록 합니다.
    • @PreAuthorize("hasRole('ADMIN')"): 특정 역할을 가진 사용자만 접근 가능하도록 합니다.
  • 권한 체크의 적절한 위치:
    • 비로그인 차단, 어드민 전용: @PreAuthorize를 컨트롤러에 사용하여 처리합니다.
    • 본인 리소스 접근 제어: 서비스 로직 내에서 userId 비교를 통해 직접 처리해야 합니다.

이해한 내용

이번 학습을 통해 Flyway 도입 시점과 DB 스키마 변경 관리 방식에 대한 명확한 이해를 얻었습니다. 특히 ddl-auto: validate 옵션과 DDL/DML의 역할 분리를 통해 JPA와 Flyway를 조화롭게 사용하는 방법을 알게 되었습니다.

또한, 스프링 시큐리티의 SecurityContext, JWT, 그리고 @AuthenticationPrincipal, @PreAuthorize와 같은 어노테이션들의 동작 원리를 깊이 있게 이해했습니다. 이를 통해 API 개발 시 사용자 인증 및 인가 처리를 더욱 안전하고 효율적으로 구현할 수 있게 되었습니다. CustomUserDetails와 같은 사용자 정의 객체를 통해 인증 정보를 활용하는 방안도 명확히 파악했습니다.

실전 적용

  • DB 스키마 변경: 앞으로 팀 내에서 DB 스키마 변경이 필요할 경우, ddl-auto: validate를 설정하고 Flyway SQL 파일을 먼저 작성한 후, 엔티티 수정을 진행하는 절차를 따를 것입니다.
  • API 인증 및 인가: 새로운 API 개발 시, @PreAuthorize와 @AuthenticationPrincipal을 활용하여 인증 및 인가 로직을 명확하게 구현할 것입니다. 특히, 본인 리소스 접근 제어와 같은 민감한 부분은 서비스 로직 내에서 철저히 검증하도록 하겠습니다.
  • CustomUserDetails 활용: CustomUserDetails에서 userId를 안전하게 꺼내오는 메서드 이름과 hasRole 사용 시 정확한 role 문자열을 파악하여, 실제 코드 작성 시 올바르게 적용할 계획입니다.

추가 학습 계획

  • Spring Security 공식 문서 심층 학습: @AuthenticationPrincipal 및 @PreAuthorize에 대한 스프링 시큐리티 공식 문서의 예제 코드를 더 자세히 살펴보며 다양한 활용 사례를 익힐 예정입니다.
  • CustomUserDetails 구현 방식 조사: CustomUserDetails 클래스가 공통 모듈에서 어떻게 구현되는지, 그리고 userId 외에 어떤 정보들을 포함하고 활용할 수 있는지 더 깊이 공부해보고 싶습니다.
  • 예외 처리 전략: 인증 실패 시 발생하는 예외(예: ForbiddenException)들을 공통 모듈에서 어떻게 통합 관리하고, 개별 모듈에서 어떻게 처리하는지에 대한 학습도 이어갈 계획입니다.

참고 자료