NGINX + SpringBoot + GeoIP2 접속국가판별

공부는 혼자하는 거·2023년 4월 24일
2

Spring Tip

목록 보기
37/52

요구사항

사용자 IP를 직접 DB에 저장하는 건 리스크가(법적인 문제) 있다고 판단. 대신 접속국가를 판별해 DB에 저장시키는 로직을 작성하자.
우리 서버는 NGINX가 프록시 서버 역할을 하고 있다.
MAXMIND GeoIP는 client Ip를 이용해서 대략적인 국가를 판별해줄 수 있는 API를 제공해준다. 회원가입 후 GeoLite2(무료) 를 다운받아준다.
GeoLite2-Country.mmdb 를 다운받아주면 된다.

https://www.maxmind.com/en/accounts/857046/geoip/downloads

nginx conf

  location / { # location 이후 특정 url을 처리하는 방법을 정의(여기서는 / -> 즉, 모든 request)
      proxy_pass $dev_url; # Request에 대해 어디로 리다이렉트하는지 작성. 8443 -> 자신의 springboot app이사용하는 포트
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # real iop
      proxy_set_header Host $http_host;

      add_header 'Cross-Origin-Embedder-Policy' 'credentialless';
      add_header 'Cross-Origin-Opener-Policy' 'same-origin';	
  }

gradle 의존성

   implementation("com.maxmind.geoip2:geoip2:4.0.1")

Utilis 클래스

object ServletUtil {

    private val log = KotlinLogging.logger { }

    fun printAllRequestHeaders() {

        val headerNames: Enumeration<String> = getCurrentRequest().headerNames
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                val name = headerNames.nextElement()
                val value: String = getCurrentRequest().getHeader(name)
                log.info("Header ::: $name : $value")
            }
        }
    }


    fun getCurrentRequest(): HttpServletRequest {
        //request가 없는 상황에서는 null pointer exception이 발생할 여지.. 리팩토링 대상..
        return (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).request
    }


    fun getRealClientIp(): String {

        val currentRequest = getCurrentRequest()

        printAllRequestHeaders()
        //x-forwarded-for
        return currentRequest.getHeader("X-Forwarded-For")?.split(",")?.firstOrNull()
            ?: currentRequest.getHeader("X-Real-IP") //nginx IP
            ?: currentRequest.getHeader("Proxy-Client-IP")
            ?: currentRequest.getHeader("WL-Proxy-Client-IP")
            ?: currentRequest.getHeader("HTTP_CLIENT_IP")
            ?: currentRequest.getHeader("HTTP_X_FORWARDED_FOR")
            ?: currentRequest.remoteAddr
    }


}

GeoReader

# yml 설정

geoip2:
  path: /Users/stella/Desktop/company/codework/back/src/main/resources/GeoLite2-Country.mmdb

@Component
class GeoReader(

) {

    private val log = KotlinLogging.logger {  }

    @Value("\${geoip2.path}")
    private lateinit var geoIpPath:String

    lateinit var database:File
    lateinit var dbReader: DatabaseReader
    
    
    @PostConstruct
    fun init(){
        println(geoIpPath)
        this.database = File(geoIpPath)
        this.dbReader = DatabaseReader.Builder(database).build()
    }


    fun getCountryCode(ipAddress: InetAddress): String {
        println("ipAddress=>$ipAddress")
        try {
            val countryResponse = dbReader.country(ipAddress)
            log.info { "isoCode: ${countryResponse.country.isoCode}"}
            return countryResponse.country.isoCode
        }catch (e: Exception){
            log.error { e.message }
            return  ""
        }
    }


}
geoReader.getCountryCode(InetAddress.getByName(ServletUtil.getRealClientIp()))

참고

https://www.baeldung.com/geolocation-by-ip-with-maxmind

https://jinsiri.tistory.com/606?category=792858

https://emgc.tistory.com/138

https://bactoria.github.io/2019/10/11/Ip%EB%A1%9C-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%A0%91%EC%86%8D-%EC%9C%84%EC%B9%98-%EC%A0%95%EB%B3%B4-%EC%95%8C%EC%95%84%EB%82%B4%EA%B8%B0/

profile
시간대비효율

0개의 댓글