获取请求来源IP
方法一:hutool获取
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.8</version>
</dependency>
代码
String tagIp = ServletUtil.getClientIP(HttpServletRequest request);
方法二:自定义方法
public String getIpAddr(HttpServletRequest request) {
final String UNKNOWN = "unknown";
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
注意:第二种获取是通常做法,但是当请求多次转发是,请求头"X-Forwarded-For"会有多个ip地址“,”拼接 下面是改良版的(改版自cloud.tencent.com/developer/a…)
public class IpUtils {
public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");
public static String longToIpV4(long longIp) {
int octet3 = (int) ((longIp >> 24) % 256);
int octet2 = (int) ((longIp >> 16) % 256);
int octet1 = (int) ((longIp >> 8) % 256);
int octet0 = (int) ((longIp) % 256);
return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
}
public static long ipV4ToLong(String ip) {
String[] octets = ip.split("\\.");
return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16)
+ (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
}
public static boolean isIPv4Private(String ip) {
long longIp = ipV4ToLong(ip);
return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255"))
|| (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255"))
|| longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
}
public static boolean isIPv4Valid(String ip) {
return pattern.matcher(ip).matches();
}
public static String validIPAddress(String IP) {
if (isIPv4(IP)) {
return "IPv4";
}
if (isIPv6(IP)) {
return "IPv6";
}
return "Neither";
}
public static boolean isIPv4(String s) {
return s.matches("^(((([0-9]{1}){1})|(([1-9]{1}[0-9]{1}){1})|((1{1}[0-9]{2}){1})|((2{1}[0-4]{1}[0-9]{1}){1})"
+ "|((2{1}5{1}[0-5]{1}){1})){1}\\.){3}(((([0-9]{1}){1})|(([1-9]{1}[0-9]{1}){1})|((1{1}[0-9]{2}){1})"
+ "|((2{1}[0-4]{1}[0-9]{1}){1})|((2{1}5{1}[0-5]{1}){1})){1})$");
}
public static boolean isIPv6(String s) {
return s.matches("^(((([0-9]|[a-f]|[A-F]){1,4}){1}:{1}){7})((([0-9]|[a-f]|[A-F]){1,4}){1})$");
}
public static String getIpFromRequest(HttpServletRequest request) {
String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
String ip = null;
for (String header : headers) {
boolean found = false;
ip = request.getHeader(header);
if (StringUtils.isNotBlank(ip) && "unknown".equalsIgnoreCase(ip)) {
StrTokenizer tokenizer = new StrTokenizer(ip, ",");
while (tokenizer.hasNext()) {
ip = tokenizer.nextToken().trim();
if (isIPv4Valid(ip) && !isIPv4Private(ip)) {
found = true;
break;
}
}
}
if (!found) {
ip = request.getRemoteAddr();
}
}
return ip;
}
}
ip匹配
全量匹配 127.0.0.1
ipWhiteList.stream().anyMatch("127.0.0.1"::contains)
区间匹配 127.0.0.1-127.0.0.3
ipWhiteList.stream().anyMatch(o -> ipMatch("127.0.0.1", o)
/**
* ip白名单匹配
*
* @param tagIp 目标ip
* @param ruleIp 规则ip
* @return 匹配成功1,否0
*/
private boolean ipMatch(String tagIp, String ruleIp) {
if (ruleIp.contains("-")) {
String[] split = ruleIp.split("-");
long start = ip2Long(split[0]);
long end = ip2Long(split[1]);
long tag = ip2Long(tagIp);
return start < tag && tag < end;
} else {
return ruleIp.equals(tagIp);
}
}
/**
* 将字符串表示的ip地址转换为long表示.
*
* @param ip ip地址
* @return 以32位整数表示的ip地址
*/
private long ip2Long(final String ip) {
final String[] ipNums = ip.split("\\.");
return (Long.parseLong(ipNums[0]) << 24)
+ (Long.parseLong(ipNums[1]) << 16)
+ (Long.parseLong(ipNums[2]) << 8)
+ (Long.parseLong(ipNums[3]));
}
模糊匹配 127.0.0.*
//替换为正则匹配 ReUtil为hutool工具类
ipWhiteList.stream().anyMatch(o -> ReUtil.contains(o.replace(".", "\\.").replace("*", "\\d{1,3}"),tagIp));
//一分为二 0-255
ipWhiteList.stream().anyMatch(o -> {
String o2 = o + "";
long start = ip2Long(o.replace("*", "0"));
long end = ip2Long(o2.replace("*", "255"));
long tag = ip2Long(tagIp);
return start < tag && tag < end;
});