Spring Hateoas links https 스키마 적용

Proxy Server나 Load Balancer를 통해 Restful API Service로 요청을 하면 Hateoas links의 스키마가 https가 아닌 http로 생성되는 현상이 있습니다. 이를 해결 하는 방법에 대해 알아보겠습니다.

Nginx에서 X-Forwarded-Proto를 Restful API Service로 전달합니다.

 location / {
        proxy_set_header    Host $http_host;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Prefix $http_x_forwarded_prefix;
        proxy_set_header    X-Forwarded-Proto https;
        proxy_set_header    X-NginX-Proxy true;
        proxy_redirect off;
        charset utf-8;
        proxy_pass http://api-backend;
 }

Restful API Service에서 다음과 같이 hateoas links를 생성합니다.

public CompanyModel toModel(Company entity) {
    return entity.toModel()
        .add(getSelfLink(entity.getCmpnyCd()));
}
...
private Link getSelfLink(String cmpnyCd) {
    return linkTo(methodOn(CompanyController.class)
                  .detailCompany(cmpnyCd))
        .withSelfRel()
        .withType(HttpMethod.GET);
}

페이지 요청의 Response 결과

{
   "_embedded":{
      "companyModelList":[
         {
            "cmpnyCd":"1017006750",
            "cmpnyNm":"테스트",
            "bizMemNo":"1234567890",
            "dfltAddr":"서울 종로구 사직로 161 경복궁",
            "_links":{
               "self":{
                  "href":"http://api주소/v1/company/1017006750",
                  "type":"GET"
               }
            }
         },
         ...
      ]
   },
   "_links":{
      "first":{
         "href":"http://api주소/v1/company/query?page=0&size=10"
      },
      "self":{
         "href":"http://api주소/v1/company/query?page=0&size=10"
      },
      "next":{
         "href":"http://api주소/v1/company/query?page=1&size=10"
      },
      "last":{
         "href":"http://api주소/v1/company/query?page=100&size=10"
      }
   },
   "page":{
      "size":10,
      "totalElements":100,
      "totalPages":100,
      "number":0
   }
}

응답에서 href가 https가 아닌 http로 설정된 것을 확인할 수 있습니다.

image-20220610113736068

그림 출처: https://tomgregory.com/spring-boot-behind-load-balancer-using-x-forwarded-headers/

이런 현상을 해결 하기 위해서 위 그림 처럼 Spring에서 ForwardedHeaderFilter을 등록하면 해결됩니다.

Proxy Server(Nginx)

Spring Cloud Gateway

Spring framework 5.0~ 또는 Spring Boot 2.0 ~

Spring Security

Spring cloud gateway

application.yml

server:
  forward-headers-strategy: native 

Spring service

application.yml

server:
  forward-headers-strategy: native

forward-headers-strategy: native는 proxy server 또는 load-balancer에서 넘겨준 forward-headers 값을 그대로 사용하도록 합니다.

forwardedHeaderFilter 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {
    ...
    @Bean
    public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
        FilterRegistrationBean<ForwardedHeaderFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new ForwardedHeaderFilter());
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}

댓글남기기