API Gateway 기반 인증 아키텍처에서 사용자 도메인 서비스 구현하기

인증된 사용자 도메인 서비스 는 마이크로서비스 아키텍처에서 인증은 일반적으로 API Gateway에서 처리되고, 각 도메인 서비스는 인증된 요청만을 받아 실제 비즈니스 로직을 수행한다.
이 글에서는 Spring Cloud Gateway에서 JWT 인증을 처리하고, 도메인 서비스(user-service)는 인증된 사용자 정보만을 활용하는 방식으로 사용자 정보를 제공하는 구조를 다룬다.

1. 아키텍처 개요

  • Gateway에서 JWT 검증 및 권한 체크
  • user-service는 인증된 사용자 ID만 받아 사용자 정보 제공
  • 모든 서비스는 stateless 구조 유지
[Client] ──▶ [Gateway (JWT 검증)] ──▶ [user-service]
                        
                        └─▶ X-User-Id 헤더 전달

2. Gateway 보안 설정

  • SecurityConfig에서 /api/user/**는 인증 필요
  • JWT 검증을 통해 유효한 사용자 요청만 통과
@EnableWebFluxSecurity
class SecurityConfig {
    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http
            .authorizeExchange {
                it.pathMatchers("/api/user/**").authenticated()
                    .pathMatchers("/api/public/**").permitAll()
                    .anyExchange().denyAll()
            }
            .oauth2ResourceServer { it.jwt() }
            .build()
    }
}

3. 사용자 ID 전달을 위한 Gateway 필터 (예시)

@Component
class JwtHeaderRelayFilter : GatewayFilterFactory<Any>() {
    override fun apply(config: Any?) = GatewayFilter { exchange, chain ->
        val token = exchange.request.headers.getFirst("Authorization")?.removePrefix("Bearer ")
        val claims = parseJwt(token) // JWT 파싱 로직 필요
        val userId = claims["sub"] as String
        val mutatedRequest = exchange.request.mutate()
            .header("X-User-Id", userId)
            .build()
        chain.filter(exchange.mutate().request(mutatedRequest).build())
    }
}

위 예시는 직접 구현하는 방식이고, 경우에 따라 Spring Cloud GatewayPrincipal 기반으로도 구현 가능.

  • 게이트웨이를 통하지 않고 호출하게되면 이렇게 헤더에 빈값으로 요청이 온다.
curl --location 'http://localhost:8082/hello'

2025-07-01T10:39:50.235+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : === Gateway Header Information ===<br>2025-07-01T10:39:50.236+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : X-User-Id: NOT_PROVIDED<br>2025-07-01T10:39:50.236+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : X-Username: NOT_PROVIDED<br>2025-07-01T10:39:50.236+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : ===================================
  • 게이트웨이를 통해 엑세스 토큰을 포함해서 호출하게되면 이렇게 헤더에 사용자 식별정보가 포함된 요청이 온다.
curl --location 'http://localhost:8080/api/user/hello' \
--header 'Authorization: ••••••'

2025-07-01T10:39:50.235+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : === Gateway Header Information ===<br>2025-07-01T10:39:50.236+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : X-User-Id: NOT_PROVIDED<br>2025-07-01T10:39:50.236+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : X-Username: NOT_PROVIDED<br>2025-07-01T10:39:50.236+09:00  INFO 66379 --- [nio-8082-exec-5] c.example.user.service.HelloController   : ===================================

5. user-service: 비즈니스 로직만

  • 인증은 Gateway에서 처리되므로 spring-boot-starter-security 불필요
  • 사용자 ID는 헤더(X-User-Id)로 전달됨
@RestController
@RequestMapping("/api/user")
class UserController(private val userService: UserService) {

    @GetMapping("/me")
    fun getUserInfo(@RequestHeader("X-User-Id") userId: String): ResponseEntity<UserInfo> {
        val user = userService.getUserById(userId)
        return ResponseEntity.ok(user)
    }
}

6. 게이트웨이 연동

Gateway에서 /api/user/** 경로는 인증 필터를 거쳐야 하며, JWT가 유효한 경우에만 user-service로 전달된다.
이를 통해 인증된 사용자만 접근 가능하도록 제어된다.

인증된 사용자만 접근 가능한 도메인 서비스는 MSA에서 핵심적인 역할을 한다.
JWT 기반의 인증 흐름과 Spring Security 설정을 적절히 활용하면, 안전하고 확장성 있는 사용자 서비스 아키텍처를 구현할 수 있다.

7. 테스트 결과

  • 엑세스 토큰 없이 user-service 에 접근하면 401 권한 없음 에러가 뜨는걸 확인 할 수 있다.
  • auth-service 를 통해 발급받은 엑세스 토큰을 입력하면 user-service 에 접근하면 접근이 가능하다

이전편 보기
Config Server 로 마이크로서비스 공통 설정 관리

참고

자세한 코드는 아래 저장소에서 확인 가능하다.
Github – 저장소

댓글 남기기