如果只是想知道如何通过ip获取所在地城市信息,可直接看第三步.
如果搭建自己的支付平台,异地支付限制是必不可少的一环.因为市面上一些非法份子,会使用我们平台生成的付款码进行欺诈行为.这也是我们必须杜绝的一种现象.因此限制异地支付就是其中一种手段.
在上一篇文章【三方支付】java如何获取请求的来源ip 我们可以获取到用户发起支付时的ip,我们只需要再获取到用户扫码时的ip进行对比,即可知道当前是否为异地支付.当然我们不能直接对比ip,因为用户通常使用pc端发起支付获取付款码,而支付时采用的是移动端.两端未必处于同一个网络,因此ip也是不同的.
- 第一步,如果我们接入是三方支付,通常三方支付会返回给我们一个二维码地址,或者收银台地址,这时候用户扫码时进入的就是三方支付的支付页面,我们是无法获取到用户ip的,这时候我们需要做的便是生成自己的二维码,用户扫描二维码进入是我们自己的页面(也可以是接口,获取ip之后直接跳转到三方支付,通常是制作一个移动端的页面,展示一些订单信息和风险提示等),只要经过我们的服务就可以拿到用户扫码时的ip了.
- 第二步,对比ip所在城市的信息.通过上面的步骤,我们拿到发起支付时的ip和扫码时的ip.我们就可以通过ip对应的城市进行对比了.目前市面上通过ip获取城市的开放接口有很多,基本都是收费的,免费的通常ip库不全,有可能查不到地址.类似 百度地图,高德地图 都有响应的接口供大家使用.也可以到阿里云市场进行购买(相对优惠很多).
- 第三步, 如何通过ip获取这里我们介绍一种免费的,内置在我们自己系统的一种获取ip城市信息的方式,这种方式既省钱又不需要担心网络问题
1. 引入 ip2region ,据ip2region官方给出的数据,ip准确率达到99.9%,而且查询速度也非常客观,可以满足我们的需求
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>2.7.0</version>
</dependency>
2. 导入ip2region的数据包
可以到官方进行下载xdb文件,并将文件放置到项目的resources下
3. 编写自己的工具类
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.core.io.ClassPathResource;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class Ip2Region {
protected static Searcher searcher;
static {
ClassPathResource resource = new ClassPathResource("ip2region/ip2region.xdb");
try (InputStream inputStream = resource.getInputStream()) {
byte[] cBuff = IoUtil.readBytes(inputStream);
searcher = Searcher.newWithBuffer(cBuff);
} catch (IOException e) {
log.error("获取ip文件失败", e);
}
}
/**
* 根据ip从 ip2region.db 中获取地理位置
*
* @param ip
* @return 地理位置
*/
public static Map<String, String> getCityInfo(String ip) {
//数据格式: 国家|区域|省份|城市|ISP
//192.168.31.160 0|0|0|内网IP|内网IP
//47.52.236.180 中国|0|香港|0|阿里云
//220.248.12.158 中国|0|上海|上海市|联通
//164.114.53.60 美国|0|华盛顿|0|0
HashMap<String, String> cityInfo = new HashMap<>(7);
try {
String searchIpInfo = searcher.search(ip);
log.info("ip查询:{},查询结果:{}", ip, searchIpInfo);
if (StrUtil.isNotBlank(searchIpInfo)) {
String[] splitIpInfo = searchIpInfo.split("\\|");
cityInfo.put("ip", ip);
cityInfo.put("searchInfo", searchIpInfo);
cityInfo.put("country", splitIpInfo[0]);
cityInfo.put("region", splitIpInfo[1]);
cityInfo.put("province", splitIpInfo[2]);
cityInfo.put("city", splitIpInfo[3]);
cityInfo.put("ISP", splitIpInfo[4]);
return cityInfo;
}
} catch (Exception e) {
log.info("failed to search({}): {}", ip, e);
}
return null;
}
/**
* 根据ip从 ip2region.db 中获取省份
*
* @param ip
* @return 地理位置
*/
public static String getProvince(String ip) {
Map<String, String> cityInfo = getCityInfo(ip);
if (cityInfo != null) {
return cityInfo.get("province");
}
else {
return null;
}
}
}
4. 使用方式 这里我们获取的是省份,也可以通过实际情况进行调整
// 获取扫码时的ip
String clientIp = IpUtil.getClientIp();
String city1 = Ip2Region.getProvince(clientIp);
// 获取下单时的ip
String city2 = Ip2Region.getProvince(order.getClientIp());
log.info("订单校验ip,订单号:{},下单ip:{},支付ip:{}", id, order.getClientIp(), clientIp);
if (StrUtil.isNotBlank(city1) && StrUtil.isNotBlank(city2) && !city1.equals(city2)) {
return Result.res(ResultEnum.IP_ERROR);
}
以上就是通过ip对比省份,进行异地支付的限制