Ip로 클라이언트 접속 위치 정보 알아내기
Google Analytics 를 이용하면 접속한 클라이언트의 위치를 제공받을 수 있다.
우째하누~ 궁금해서 찾아봤다.
클라이언트 접속 시 국가와 도시 정보를 응답해주도록 만들어보쟈~
위치정보 다운받기
MAXMIND 에서 제공해주는 DB를 이용하면 IP Address를 이용하여 대략적인 위치 정보를 얻을 수가 있다.
https://dev.maxmind.com/geoip/geoip2/geolite2/
GeoLite2 City
: 국가 정보 제공
GeoLite2 Country
: 국가, 도시 정보 제공
GeoLite2 말고 GeoIp2도 있는데,
이 둘의 차이점은 GeoLite2 는 무료이고 GeoIp2는 유료다.
(CSV로 다운로드 받으면 국가, 도시 정보를 확인해 볼 수 있다.)
의존성 추가
자바 의존성을 추가해준다.
(Maven)
1
2
3
4
5
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.12.0</version>
</dependency>
(Gradle)
1
2
3
4
5
6
repositories {
mavenCentral()
}
dependencies {
compile 'com.maxmind.geoip2:geoip2:2.12.0'
}
콛잉
빈등록
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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클래스
1
2
3
4
5
6
@Getter
@AllArgsConstructor
public class GeoLocationDto {
private String subdivisionName;
private String cityName;
}
RestController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@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;
}
}
결과
위의 주소를 보면 알 수 있듯이 ngrok으로 배포해서 접속했다.
로컬에서 테스트하면 127.0.0.1
로 떠서 위치정보를 알 수 없기 때문에 ngrok으로 해결했다.
(ngrok은 외부에서 로컬 서버에 접속할 수 있도록 도와주는 터널 프로그램이다. )
여기서 subdivision이 서울로 나왔지만 특별시, 광역시 등은 subdivision으로 분류되는 듯 하다.
(경상남도, 경상북도 등도 subdivision이고, 마산, 용인 등은 city이다.)
위치 정보는 정확한가?
위의 cityName를 보면 강동구
로 떴는데, 사실 난 강남구(역삼)
에 있었다.
저녁에 역삼의 어느 카페에서 테스트를 다시 해보았다.
(GeoLocationDto에 위도, 경도를 추가함)
오오!! 강남구 떴다~~
위도, 경도를 구글맵에 쳐보면!!
종로구
로 나온다…ㅜ
ipfingerprints 에 접속하면 해당 ip address의 ISP, 경도, 위도, 국가, 도시 정보를 알 수 있다.
그리고 하단에는 아래와 같이 나와있다.
IP 주소 위치 정보는 MaxMind를 이용하여 제공하고 있습니다. MaxMind에서 제공하는 국가 정보는 99.8 % 정확합니다. 미국의 주 정보는 90 % 정확헙니다. 미국 도시 정보가 반경 50km 이내일 확률은 81 % 입니다.
정확하게 일치하는 것이 아닌 대략적인 위치다.
사실 공짜로 쓰는데 이정도 알려주는 것만으로도 좋은 것 같다.
url 단축기에 적용해 볼 만한 것 같다