Pre Merge pull request !651 from wuzhiming/ipv6-support

This commit is contained in:
wuzhiming 2025-03-10 03:12:46 +00:00 committed by Gitee
commit 1a1af540dc
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
6 changed files with 103 additions and 24 deletions

View File

@ -39,7 +39,7 @@
<justauth.version>1.16.7</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<geoip2.version>4.2.1</geoip2.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<aws.crt.version>0.31.3</aws.crt.version>
@ -320,6 +320,12 @@
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>${geoip2.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 MiB

View File

@ -94,6 +94,12 @@
<artifactId>ip2region</artifactId>
</dependency>
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,11 +1,13 @@
package org.dromara.common.core.utils.ip;
import cn.hutool.core.net.NetUtil;
import cn.hutool.http.HtmlUtil;
import org.dromara.common.core.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 获取地址类
@ -17,17 +19,19 @@ import lombok.extern.slf4j.Slf4j;
public class AddressUtils {
// 未知地址
public static final String UNKNOWN = "XX XX";
public static final String UNKNOWN = "未知";
public static String getRealAddressByIP(String ip) {
if (StringUtils.isBlank(ip)) {
return UNKNOWN;
}
// 内网不查询
ip = StringUtils.contains(ip, "0:0:0:0:0:0:0:1") ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
if (NetUtil.isInnerIP(ip)) {
return "内网IP";
ip = HtmlUtil.cleanHtmlTag(ip).trim();
try {
InetAddress ipAddress = InetAddress.getByName(ip);
return RegionUtils.getCityInfo(ipAddress);
} catch (UnknownHostException e) {
log.error("IP地址离线获取城市异常 {}", ip);
return UNKNOWN;
}
return RegionUtils.getCityInfo(ip);
}
}

View File

@ -3,16 +3,26 @@ package org.dromara.common.core.utils.ip;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.ObjectUtil;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse;
import com.maxmind.geoip2.record.City;
import com.maxmind.geoip2.record.Country;
import com.maxmind.geoip2.record.Subdivision;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.file.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.File;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Locale;
/**
* 根据ip地址定位工具类离线方式
* 参考地址<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">集成 ip2region 实现离线IP地址定位库</a>
*
* @author lishuyan
*/
@ -20,19 +30,22 @@ import java.io.File;
public class RegionUtils {
private static final Searcher SEARCHER;
private static final DatabaseReader reader;
private static final String locale;
static {
String fileName = "/ip2region.xdb";
File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
if (!FileUtils.exist(existFile)) {
ClassPathResource fileStream = new ClassPathResource(fileName);
//ipv4初始化
String fileName4 = "/ip2region.xdb";
File existFile4 = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName4);
if (!FileUtils.exist(existFile4)) {
ClassPathResource fileStream = new ClassPathResource(fileName4);
if (ObjectUtil.isEmpty(fileStream.getStream())) {
throw new ServiceException("RegionUtils初始化失败原因IP地址库数据不存在!");
throw new ServiceException("RegionUtils初始化失败原因IPv4地址库数据不存在!");
}
FileUtils.writeFromStream(fileStream.getStream(), existFile);
FileUtils.writeFromStream(fileStream.getStream(), existFile4);
}
String dbPath = existFile.getPath();
String dbPath = existFile4.getPath();
// 1 dbPath 加载整个 xdb 到内存
byte[] cBuff;
@ -47,21 +60,69 @@ public class RegionUtils {
} catch (Exception e) {
throw new ServiceException("RegionUtils初始化失败原因" + e.getMessage());
}
//ipv6初始化
//文件来源 https://download.db-ip.com/free/dbip-city-lite-2025-03.mmdb.gz (db-ip官方免费版本中文支持不好)
//文件来源 https://gitee.com/allen0769/GeoLite.mmdb.git
String fileName6 = "/GeoLite2-City.mmdb";
File existFile6 = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName6);
if (!FileUtils.exist(existFile6)) {
ClassPathResource fileStream = new ClassPathResource(fileName6);
if (ObjectUtil.isEmpty(fileStream.getStream())) {
throw new ServiceException("RegionUtils初始化失败原因IP6地址库数据不存在");
}
FileUtils.writeFromStream(fileStream.getStream(), existFile6);
}
try {
reader = new DatabaseReader.Builder(existFile6).build();
} catch (IOException e) {
throw new ServiceException("RegionUtils初始化失败原因从GeoLite2-City.mmdb文件加载内容失败" + e.getMessage());
}
locale = Locale.getDefault().toString().replace("_", "-");
}
/**
* 根据IP地址离线获取城市
*/
public static String getCityInfo(String ip) {
public static String getCityInfo(InetAddress ipAddress) {
try {
ip = ip.trim();
// 3执行查询
String region = SEARCHER.search(ip);
return region.replace("0|", "").replace("|0", "");
if (ipAddress.isSiteLocalAddress() || ipAddress.isLinkLocalAddress() || ipAddress.isLoopbackAddress()) {
return "内网IP";
}
if (ipAddress instanceof Inet4Address) {
return getCityInfoIpv4(ipAddress);
} else if (ipAddress instanceof Inet6Address) {
return getCityInfoIpv6(ipAddress);
} else {
return "未知";
}
} catch (Exception e) {
log.error("IP地址离线获取城市异常 {}", ip);
log.error("IP地址 {} 离线获取城市异常 {}", ipAddress.getAddress(), e.getMessage());
return "未知";
}
}
/**
* 根据IPV4地址离线获取城市
*/
private static String getCityInfoIpv4(InetAddress ipAddress) throws Exception {
String region = SEARCHER.search(ipAddress.getHostAddress());
//中国|江苏省|南京市|电信
return region.replace("0|", "").replace("|0", "");
}
/**
* 根据IPV6地址离线获取城市
*/
private static String getCityInfoIpv6(InetAddress ipAddress) throws IOException, GeoIp2Exception {
CityResponse cityResponse = reader.city(ipAddress);
Country country = cityResponse.getCountry();
Subdivision subdivision = cityResponse.getMostSpecificSubdivision();
City city = cityResponse.getCity();
String countryStr = country.getNames().get(locale) != null ? country.getNames().get(locale) : country.getName();
String subdivisionStr = subdivision.getNames().get(locale) != null ? subdivision.getNames().get(locale) : subdivision.getName();
String cityStr = city.getNames().get(locale) != null ? city.getNames().get(locale) : city.getName();
return countryStr + "|" + subdivisionStr + "|" + cityStr;
}
}

View File

@ -39,10 +39,12 @@ http {
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name localhost;
# https配置参考 start
#listen 443 ssl;
#listen [::]:443 ssl ipv6only=on;
# 证书直接存放 /docker/nginx/cert/ 目录下即可 更改证书名称即可 无需更改证书路径
#ssl on;