Spring 개발일지

[팀프로젝트] MSA 기반 티켓팅 프로그램 - AuthContext 적용 및 공통 모듈 업데이트

김둘리 2026. 5. 12. 09:00

기존에 @RequestHeader("X-User-Id")로 userId를 받던 방식을 공통 모듈 0.0.4 업데이트로 AuthContext로 교체했다.

1. 기존 방식의 문제

// 기존 - 모든 API마다 헤더 파라미터 선언
@GetMapping("/{paymentId}")
public ResponseEntity<ApiResponse<PaymentResponse>> getPayment(
        @PathVariable UUID paymentId,
        @RequestHeader("X-User-Id") UUID userId) {  // 매번 선언해야 함

모든 API마다 @RequestHeader("X-User-Id") UUID userId를 선언해야 했다. 파라미터가 늘어나고 코드가 지저분해졌다.


2. common 0.0.4 - AuthContext

공통 모듈 0.0.4에 AuthContext가 추가됐다.

import com.firstticket.common.web.AuthContext;

UUID userId = AuthContext.getUserId();   // X-User-Id → UUID
String role = AuthContext.getRole();     // X-User-Role → String

Gateway가 JWT에서 추출한 X-User-Id, X-User-Role 헤더를 정적 메서드로 가져올 수 있다.

컨트롤러 파라미터 선언 없이 필요한 시점에 어디서든 호출 가능하다.


3. PaymentController 교체

// 변경 후 - 파라미터 제거, 필요한 시점에 호출
@GetMapping("/{paymentId}")
public ResponseEntity<ApiResponse<PaymentResponse>> getPayment(
        @PathVariable UUID paymentId) {
    UUID userId = AuthContext.getUserId();  // 헤더에서 자동 추출
    ...
}

@GetMapping("/me")
public ResponseEntity<ApiResponse<List<PaymentResponse>>> getMyPayments() {
    UUID userId = AuthContext.getUserId();
    ...
}

@PostMapping("/{paymentId}/refund")
public ResponseEntity<ApiResponse<PaymentResponse>> refundPayment(
        @PathVariable UUID paymentId,
        @RequestBody @Valid PaymentRefundRequest request) {
    UUID userId = AuthContext.getUserId();
    ...
}

파라미터가 깔끔해졌다.


4. AuthContext를 각 메서드마다 호출하는 이유

처음에는 클래스 레벨에서 한 번만 뽑아두면 되지 않냐고 생각했다.

// 이렇게 하면 안 됨
private final UUID userId = AuthContext.getUserId(); // ❌

AuthContext.getUserId()는 HTTP 요청 스레드에서 헤더를 읽어오는 거라 요청마다 다른 값이 나온다. 클래스 레벨에서 한 번만 뽑아두면 첫 번째 요청의 userId가 고정되어버린다.

그래서 각 메서드 실행 시점에 호출해야 한다.


5. 코드래빗 리뷰 - Infrastructure 레이어 분리

코드래빗이 AuthContext를 Controller에서 직접 호출하지 말고 Infrastructure 레이어에서 래핑해서 사용하라고 지적했다.

// Infrastructure 레이어에서 래핑
@Component
public class AuthContextAdapter {
    public UUID getCurrentUserId() {
        return AuthContext.getUserId();
    }
    public String getCurrentUserRole() {
        return AuthContext.getRole();
    }
}

DDD 관점에서는 맞는 말이다. 외부 모듈 의존성을 Controller가 직접 알면 안 된다.

근데 AuthContext는 헤더에서 값만 읽어오는 단순 유틸리티라서 실용적으로는 Controller에서 직접 써도 문제없다고 판단했다. 추후 팀 논의 후 결정할 예정이다.


6. build.gradle 업데이트

// 변경 전
implementation 'com.first-ticket:common:0.0.3-SNAPSHOT'

// 변경 후
implementation 'com.first-ticket:common:0.0.4-SNAPSHOT'

마무리

AuthContext 하나로 모든 API에서 userId, role을 깔끔하게 추출할 수 있게 됐다.

MSA에서 공통 모듈을 잘 활용하면 각 서비스의 코드가 훨씬 간결해진다.