正常获取ip地址,包括了请求头的X-Real-IP,X-real-ip-portal,X-real-ip-szdz
@Slf4j
public class IpUtils {
private static final String LOCAL_IPV4 = "127.0.0.1";
private static final String LOCAL_IPV6 = "0:0:0:0:0:0:0:1";
private static final int IP_COUNT_MAX = 15;
/**
* 从请求头获取IP
* @param request 请求
* @return IP | 127.0.0.1
*/
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (CheckUtils.isNotEmpty(ip)) {
return ip;
}
ip = request.getHeader("X-real-ip-portal");
if (CheckUtils.isNotEmpty(ip)) {
return ip;
}
ip = request.getHeader("X-real-ip-szdz");
if (CheckUtils.isNotEmpty(ip)) {
return ip;
}
log.warn("获取IP失败, 缺少X-Real-IP、X-real-ip-portal、X-real-ip-szdz请求头信息");
// 取不到再试试其他方式
ip = request.getRemoteAddr();
if (ip.equals(LOCAL_IPV4) || ip.equals(LOCAL_IPV6)) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
log.error("获取IP异常: " + e.getMessage(), e);
throw new RuntimeException("获取IP地址失败");
}
ip = inet.getHostAddress();
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ip != null && ip.length() > IP_COUNT_MAX) {
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return CheckUtils.isNotEmpty(ip) ? ip : "127.0.0.1";
}
/**
* 判断IP是否在IP名单中
* @param targetIp 目标ip地址
* @param ipList ip名单, 可能存在通配符
* @return true-匹配, false-不匹配
*/
public static boolean isMatch(String targetIp, List<String> ipList) {
if (CheckUtils.isEmpty(ipList)) {
return false;
}
for (String ip : ipList) {
if (ip.contains("*") && isMatch(targetIp, ip)) {
return true;
} else if (ip.equals(targetIp)) {
return true;
}
}
return false;
}
/**
* 通配符匹配
* @param targetIp 目标IP, 比如 192.169.20.56
* @param ipRegx 匹配符, 比如 192.168.20.*
* @return true-匹配; false-不匹配
*/
public static boolean isMatch(String targetIp, String ipRegx) {
String[] pa = ipRegx.split("\\*+");
List<String> result = matches(targetIp, pa);
log.debug("{} {} => matches: {}", targetIp, ipRegx, result);
return CheckUtils.isNotEmpty(result);
}
/**
* 从input中查找通配符序列
*/
private static List<String> matches(CharSequence input, String[] patterns) {
int n = input.length(), m = patterns.length;
List<String> result = new ArrayList<>();
for (int i = 0; i < n; ) {
int left = -1, right = -1;
// 以i为起点,执行m趟匹配,每趟i至少前进p[j].length长度
for (int j = 0; j < m; j++) {
long region = lookBehind(input, i, patterns[j]);
// 模式序列的第二个开始使用贪婪匹配
if (j != 0 && region >= 0) {
long greedyRegion;
for (int k = (int) region + 1; ; k = (int) greedyRegion + 1) {
greedyRegion = lookBehind(input, k, patterns[j]);
// 贪婪找到,继续贪婪尝试
if (greedyRegion > 0) {
region = greedyRegion;
} else {
break;
}
}
}
// pattern[j]失败,则本趟失败
if (region < 0) {
i = ((int) -region) + 1;
break;
} else {
i = (int) region + 1;
if (j == 0) {
// 模式序列的第一个找到,记左边界,在高32位
left = (int) (region >> 32);
}
if (j == m - 1) {
// 模式序列的最后一个找到,记右边界,在低32位
right = (int) region;
}
}
}
if (left >= 0 && right >= 0) {
result.add(input.subSequence(left, right + 1).toString());
}
}
return result;
}
/**
* 在input的i位置开始向后扫描非贪婪查找pattern,在pattern尾匹配时回溯确认
*/
private static long lookBehind(CharSequence in, int i, CharSequence pattern) {
int len = in.length(), pLen = pattern.length(), _pMax = pLen - 1;
char pEnd = pattern.charAt(_pMax);
if (len - i >= pLen) {
for (i = i + _pMax; i < len; i++) {
// 与pa末尾相同,i即右边界
if (in.charAt(i) == pEnd || pEnd == '?') {
if (pLen == 1) {
return ((long) i) << 32 | i;
}
// 则至多回溯pLen长找左边界
for (int j = i - 1; j >= i - _pMax; j--) {
char p = pattern.charAt(_pMax - i + j);
if (in.charAt(j) == p || p == '?') {
if (j == i - _pMax) {
return ((long) j) << 32 | i;
}
} else {
break;
}
}
}
}
}
return -i;
}
}