如果只是想知道如何通过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|0HashMap<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. 使用方式 这里我们获取的是省份,也可以通过实际情况进行调整
// 获取扫码时的ipString clientIp = IpUtil.getClientIp();String city1 = Ip2Region.getProvince(clientIp);// 获取下单时的ipString 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对比省份,进行异地支付的限制