본문 바로가기
Infra System

Request between resource servers

by kellis 2020. 10. 14.

각 Resource Server는 Access Token을 필요로 합니다. 따라서 하나의 Resource Server에서 또 다른 Resource Server로 요청을 보내려면 그 요청의 Header에 Authorization을 추가해주어야 합니다. 

MSA에서는 Resource Server 간 요청이 빈번한데, 개발자가 매번 이 작업을 해주는 것은 비효율적인 일이므로 air-common-lib에서 이를 처리하려 합니다. 

이하 본문에서는 Resource Server → Resource Server 요청을 서비스간 요청이라고 하고, Client → Resource Server를 클라이언트 요청이라고 칭하겠습니다. 

 

이를 위해 필요한 작업을 크게 두 가지로 나누면,

  • 클라이언트 요청이 들어오면, 요청의 Header에 있는 값을 ThreadLocal에 저장하기.
  • 서비스 간 요청 시에, 요청에 ThreadLocal에 있는 값을 Header에 싣기.

 

클라이언트 요청의 Header에 있는 값을 ThreadLocal에 저장하기 위해 3가지 클래스를 생성했습니다. (UserContext, UserContextHolder, UserContextFilter)

서비스 간 요청을 하기 위한 API는 RestTemplate, Feign가 있는데 아래에서 하나씩 다뤄보도록 하겠습니다. 

 


1. RestTemplate

 

spring-boot-starter-web에 내장되어 있는 RestTemplate을 바로 이용하는 것이 아니라, 해당 요청에 Interceptor를 추가해 줍니다. 

@Bean
fun oauthRestTemplate(): RestTemplate = RestTemplateBuilder().build().apply {
    interceptors.add(UserContextInterceptor())
}

그 Interceptor는 UserContextHolder에 저장해놓은 값들을 요청의 Header에 추가하는 역할을 합니다. 

class UserContextInterceptor : ClientHttpRequestInterceptor {
    override fun intercept(request: HttpRequest, body: ByteArray, execution: ClientHttpRequestExecution): ClientHttpResponse = with(request.headers) {
        add(UserContext.AUTHORIZATION, UserContextHolder.getContext().authorization)
        add(UserContext.CORRELATION_ID, UserContextHolder.getContext().correlationId)
 
        execution.execute(request, body)
    }
}

2. Feign

1. Feign을 사용하기 위해 의존성을 추가해야 한다. 

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

2.Feign도 RestTemplate과 동일하게, Interceptor를 추가해줌으로써 ThreadLocal에 저장한 값을 서비스 간 요청의 Header에 싣습니다. 

spring-cloud-starter-feign에 있는 RequestInterceptor를 구현하면, 자동적으로 Interceptor로 등록됩니다. 

@Component
class CommonRequestInterceptor : RequestInterceptor{
    override fun apply(requestTemplate: RequestTemplate) {
 
        requestTemplate.header(UserContext.AUTHORIZATION, UserContextHolder.getContext().authorization)
        requestTemplate.header(UserContext.CORRELATION_ID, UserContextHolder.getContext().correlationId)
 
    }
}

3. 마지막으로, Fegin을 사용할 Resource Server에서 FeginClient임을 명시해줍니다. (Main class)

@SpringBootApplication(scanBasePackages = ["kr.sys4u.lab.airmongoprototype", "kr.sys4u.lab.aircommonlib"])
@EnableFeignClients
class AirMongoPrototypeApplication

댓글