package com.walker.web.util; import com.fasterxml.jackson.databind.node.ObjectNode; import com.walker.infrastructure.utils.JsonUtils; import com.walker.infrastructure.utils.StringUtils; import com.walker.web.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; /** * 获取IP方法 * * @author Mike */ public class IpUtils { protected static final transient Logger logger = LoggerFactory.getLogger(IpUtils.class); public static final String UNKNOWN_TEXT = "unknown"; public static final String LOCALHOST = "127.0.0.1"; /** * 获取客户端IP * * @param request 请求对象 * @return IP地址 */ public static String getIpAddr(HttpServletRequest request) { if (request == null) { return "unknown"; } String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || UNKNOWN_TEXT.equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN_TEXT.equalsIgnoreCase(ip)) { ip = request.getHeader("X-Forwarded-For"); } if (ip == null || ip.length() == 0 || UNKNOWN_TEXT.equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN_TEXT.equalsIgnoreCase(ip)) { ip = request.getHeader("X-Real-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN_TEXT.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? LOCALHOST : getMultistageReverseProxyIp(ip); } /** * 检查是否为内部IP地址 * * @param ip IP地址 * @return 结果 */ public static boolean internalIp(String ip) { byte[] addr = textToNumericFormatV4(ip); return internalIp(addr) || LOCALHOST.equals(ip); } /** * 检查是否为内部IP地址 * * @param addr byte地址 * @return 结果 */ private static boolean internalIp(byte[] addr) { if (addr == null || addr.length < 2) { return true; } final byte b0 = addr[0]; final byte b1 = addr[1]; // 10.x.x.x/8 final byte SECTION_1 = 0x0A; // 172.16.x.x/12 final byte SECTION_2 = (byte) 0xAC; final byte SECTION_3 = (byte) 0x10; final byte SECTION_4 = (byte) 0x1F; // 192.168.x.x/16 final byte SECTION_5 = (byte) 0xC0; final byte SECTION_6 = (byte) 0xA8; switch (b0) { case SECTION_1: return true; case SECTION_2: if (b1 >= SECTION_3 && b1 <= SECTION_4) { return true; } case SECTION_5: switch (b1) { case SECTION_6: return true; } default: return false; } } /** * 将IPv4地址转换成字节 * * @param text IPv4地址 * @return byte 字节 */ public static byte[] textToNumericFormatV4(String text) { if (text.length() == 0) { return null; } byte[] bytes = new byte[4]; String[] elements = text.split("\\.", -1); try { long l; int i; switch (elements.length) { case 1: l = Long.parseLong(elements[0]); if ((l < 0L) || (l > 4294967295L)) { return null; } bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 2: l = Integer.parseInt(elements[0]); if ((l < 0L) || (l > 255L)) { return null; } bytes[0] = (byte) (int) (l & 0xFF); l = Integer.parseInt(elements[1]); if ((l < 0L) || (l > 16777215L)) { return null; } bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 3: for (i = 0; i < 2; ++i) { l = Integer.parseInt(elements[i]); if ((l < 0L) || (l > 255L)) { return null; } bytes[i] = (byte) (int) (l & 0xFF); } l = Integer.parseInt(elements[2]); if ((l < 0L) || (l > 65535L)) { return null; } bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 4: for (i = 0; i < 4; ++i) { l = Integer.parseInt(elements[i]); if ((l < 0L) || (l > 255L)) { return null; } bytes[i] = (byte) (int) (l & 0xFF); } break; default: return null; } } catch (NumberFormatException e) { return null; } return bytes; } /** * 获取IP地址 * * @return 本地IP地址 */ public static String getHostIp() { try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { } return LOCALHOST; } /** * 获取主机名 * * @return 本地主机名 */ public static String getHostName() { try { return InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { } return "未知"; } /** * 从多级反向代理中获得第一个非unknown IP地址 * * @param ip 获得的IP地址 * @return 第一个非unknown IP地址 */ public static String getMultistageReverseProxyIp(String ip) { // 多级反向代理检测 if (ip != null && ip.indexOf(StringUtils.DEFAULT_SPLIT_SEPARATOR) > 0) { final String[] ips = ip.trim().split(StringUtils.DEFAULT_SPLIT_SEPARATOR); for (String subIp : ips) { if (false == isUnknown(subIp)) { ip = subIp; break; } } } return ip; } /** * 检测给定字符串是否为未知,多用于检测HTTP请求相关 * * @param checkString 被检测的字符串 * @return 是否未知 */ public static boolean isUnknown(String checkString) { return StringUtils.isEmpty(checkString) || UNKNOWN_TEXT.equalsIgnoreCase(checkString); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~ 根据IP调用第三方服务查询地理位置名称,2023-01-05 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // IP地址查询 public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; /** * 根据IP地址调用三方服务,查询位置信息: 省 市 * @param ip * @return */ public static String getLocationByIP(String ip){ // 内网不查询 if (IpUtils.internalIp(ip)) { return "内网IP"; } try { String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.CHARSET_GBK); if (StringUtils.isEmpty(rspStr)) { logger.error("获取地理位置异常 {}", ip); return UNKNOWN_TEXT; } ObjectNode objectNode = JsonUtils.jsonStringToObjectNode(rspStr); if(objectNode == null){ return StringUtils.EMPTY_STRING; } String region = objectNode.get("pro").asText(); String city = objectNode.get("city").asText(); // JSONObject obj = JSON.parseObject(rspStr); // String region = obj.getString("pro"); // String city = obj.getString("city"); return String.format("%s %s", region, city); } catch (Exception e) { logger.error("获取地理位置异常 {}", ip); return StringUtils.EMPTY_STRING; } } /** * 获取ip地址对应的城市区域信息。 * @param ip * @param restTemplate * @return * @date 2023-06-29 */ public static final Location getLocationAli(String ip, RestTemplate restTemplate){ Map map = new HashMap(); map.put("ip", ip); map.put("accessKey", "alibaba-inc"); try{ ResponseEntity entity = restTemplate.postForEntity(LOCATION_URL_TAOBAO, map, String.class); if(!entity.getStatusCode().is2xxSuccessful()){ logger.error("ip远程获取locatioin错误:" + entity.getBody()); return null; } String data = entity.getBody(); if(StringUtils.isEmpty(data)){ logger.error("ip获取location远程返回空数据,ip = " + ip); return null; } Map locationMap = JsonUtils.jsonStringToObject(data, Map.class); if ("query success".equals(locationMap.get("msg").toString())) { Location location = new Location(); location.setCountry(locationMap.get("country").toString()); location.setCity(locationMap.get("city").toString()); location.setRegion(locationMap.get("region").toString()); return location; } return null; } catch (Exception ex){ logger.error("ip获取location错误:" + ex.getMessage(), ex); return null; } } private static final String LOCATION_URL_TAOBAO = "http://ip.taobao.com/outGetIpInfo"; }