Bactoria 황준오

Ip로 클라이언트 접속 위치 정보 알아내기

2019-10-11
bactoria

Google Analytics 를 이용하면 접속한 클라이언트의 위치를 제공받을 수 있다.

우째하누~ 궁금해서 찾아봤다.

image

 

 

클라이언트 접속 시 국가와 도시 정보를 응답해주도록 만들어보쟈~

 

 

위치정보 다운받기

MAXMIND 에서 제공해주는 DB를 이용하면 IP Address를 이용하여 대략적인 위치 정보를 얻을 수가 있다.

https://dev.maxmind.com/geoip/geoip2/geolite2/

image

GeoLite2 City: 국가 정보 제공

GeoLite2 Country: 국가, 도시 정보 제공

 

GeoLite2 말고 GeoIp2도 있는데,

이 둘의 차이점은 GeoLite2 는 무료이고 GeoIp2는 유료다.

 

(CSV로 다운로드 받으면 국가, 도시 정보를 확인해 볼 수 있다.)

 

 

의존성 추가

자바 의존성을 추가해준다.

 

(Maven)

<dependency>
    <groupId>com.maxmind.geoip2</groupId>
    <artifactId>geoip2</artifactId>
    <version>2.12.0</version>
</dependency>

 

(Gradle)

repositories {
    mavenCentral()
}
dependencies {
    compile 'com.maxmind.geoip2:geoip2:2.12.0'
}

 

 

콛잉

 

빈등록

@Component
public class GeoReader {
    private static final String DATABASE_CITY_PATH = "C:\\Users\\bactoria\\Downloads\\GeoLite2-City_20191008\\GeoLite2-City.mmdb";
    private DatabaseReader reader;

    public GeoReader() throws IOException {
        File dbFile = new File(DATABASE_CITY_PATH);
        reader = new DatabaseReader.Builder(dbFile).build();
    }

    public CityResponse city(InetAddress ipAddress) {
        CityResponse response = null;

        try {
            response = reader.city(ipAddress);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (GeoIp2Exception e) {
            e.printStackTrace();
        }

        return response;
    }
}

 

service

@Service
@RequiredArgsConstructor
public class GeoService {

    private final GeoReader geoReader;

    public GeoLocation findCity(InetAddress ipAddress) {
        CityResponse response = geoReader.city(ipAddress);

        Subdivision subdivision = response.getMostSpecificSubdivision();
        City city = response.getCity();
        
        return new GeoLocationDto(subdivision.getName(), city.getName());
    }
}

 

국가, 도시 정보를 담는 DTO클래스

@Getter
@AllArgsConstructor
public class GeoLocationDto {
    private String subdivisionName;
    private String cityName;
}

 

RestController

@RestController
@RequiredArgsConstructor
public class GeoRestController {

    private final GeoService geoService;

    @GetMapping("/geo")
    public ResponseEntity<GeoLocationDto> city() {
        InetAddress ipAddress = getIpAddress();
        GeoLocationDto geoLocationDto = geoService.findCity(ipAddress);
        return ResponseEntity.ok(geoLocationDto);
    }
    
    private InetAddress getIpAddress() {
        HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

        String ip = req.getHeader("X-FORWARDED-FOR");

        if (ip == null || ip.isEmpty()) {
            ip = req.getRemoteAddr();
        }
        if (ip == null || ip.isEmpty()) {
            ip = req.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty()) {
            ip = req.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty()) {
            ip = req.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty()) {
            ip = req.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty()) {
            ip = req.getRemoteAddr();
        }
        if (ip == null || ip.isEmpty()) {
            throw new RuntimeException();
        }

        InetAddress ipAddress = null;
        try {
            ipAddress = InetAddress.getByName(ip);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        return ipAddress;
    }
}

 

결과

image

위의 주소를 보면 알 수 있듯이 ngrok으로 배포해서 접속했다.

로컬에서 테스트하면 127.0.0.1로 떠서 위치정보를 알 수 없기 때문에 ngrok으로 해결했다.

(ngrok은 외부에서 로컬 서버에 접속할 수 있도록 도와주는 터널 프로그램이다. )

 

여기서 subdivision이 서울로 나왔지만 특별시, 광역시 등은 subdivision으로 분류되는 듯 하다.

(경상남도, 경상북도 등도 subdivision이고, 마산, 용인 등은 city이다.)

 

 

위치 정보는 정확한가?

위의 cityName를 보면 강동구로 떴는데, 사실 난 강남구(역삼)에 있었다.

 

저녁에 역삼의 어느 카페에서 테스트를 다시 해보았다.

(GeoLocationDto에 위도, 경도를 추가함)

image

 

오오!! 강남구 떴다~~

위도, 경도를 구글맵에 쳐보면!!

image

종로구로 나온다…ㅜ

 

ipfingerprints 에 접속하면 해당 ip address의 ISP, 경도, 위도, 국가, 도시 정보를 알 수 있다.

그리고 하단에는 아래와 같이 나와있다.

 

IP 주소 위치 정보는 MaxMind를 이용하여 제공하고 있습니다. MaxMind에서 제공하는 국가 정보는 99.8 % 정확합니다. 미국의 주 정보는 90 % 정확헙니다. 미국 도시 정보가 반경 50km 이내일 확률은 81 % 입니다.

 

정확하게 일치하는 것이 아닌 대략적인 위치다.

사실 공짜로 쓰는데 이정도 알려주는 것만으로도 좋은 것 같다.

 

url 단축기에 적용해 볼 만한 것 같다


황준오 (Bactoria) 황준오 (Bactoria)

.

Comments

Content