사용자 IP를 직접 DB에 저장하는 건 리스크가(법적인 문제) 있다고 판단. 대신 접속국가를 판별해 DB에 저장시키는 로직을 작성하자.
우리 서버는 NGINX가 프록시 서버 역할을 하고 있다.
MAXMIND GeoIP는 client Ip를 이용해서 대략적인 국가를 판별해줄 수 있는 API를 제공해준다. 회원가입 후 GeoLite2(무료) 를 다운받아준다.
GeoLite2-Country.mmdb 를 다운받아주면 된다.
https://www.maxmind.com/en/accounts/857046/geoip/downloads
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';
}
implementation("com.maxmind.geoip2:geoip2:4.0.1")
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
}
}
# 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