HttpServletRequest、ServerHttpRequest获取访问者真实IP,并设置ip白名单

在项目记录日志的时候和网关处理IP白名单的时候,通常会获取用户IP,一般都会从HttpServletRequest、ServerHttpRequest获取访问者真实IP
1.从HttpServletRequest中获取(日志打印的情况):
public static String getIpAddr(HttpServletRequest request){
    
    
        String ip = null;

        // X-Forwarded-For:Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
    
    
            // Proxy-Client-IP:apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
    
    
            // WL-Proxy-Client-IP:weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
    
    
            // HTTP_CLIENT_IP:有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
    
    
            // X-Real-IP:nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        // 有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0)
        {
    
    
            ip = ipAddresses.split(",")[0];
        }

        // 还是不能获取到,最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
    
    
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
2.(SpringCloud-Gateway二代网关)从ServerHttpRequest中获取
public static String getIpAddress(ServerHttpRequest request) {
    
    
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
    
    
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
    
    
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    
    
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    
    
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    
    
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    
    
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    
    
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    
    
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
获取到IP后如何过滤白名单
package com.maorong.gateway.config.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

/**
 * 从nacos获取IP白名单配置信息
 *
 * @author sk
 * @DATE: 2021/5/12
 */
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "whiteip")
public class WhiteIpListProperties
{
    
    
    /**
     * 放行IP白名单配置,网关不校验此处的IP白名单
     */
    private List<String> whites = new ArrayList<>();

    public List<String> getWhites()
    {
    
    
        return whites;
    }

    public void setWhites(List<String> whites)
    {
    
    
        this.whites = whites;
    }
}

nacos配置信息:

网关添加过滤器 Filter
/**
 * 网关鉴权
 * @author sk
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered
{
    
    
    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);

    private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;

    // 排除过滤的 ip,nacos自行添加
    @Autowired
    private WhiteIpListProperties WhiteIp;
	
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
    
    
        // 跳过不需要验证的 ip白名单
        String reqIp = IPUtils.getIpAddress(exchange.getRequest());
        log.info("<<<<<<<请求的reqIp:"+reqIp);
        if (!StringUtils.matches(reqIp, WhiteIp.getWhites()))
        {
    
    
            return setUnauthorizedResponse(exchange, "没有权限访问!");
        }
        
    }
判断是否配置过ip白名单
public class StringUtils extends org.apache.commons.lang3.StringUtils{
    
    
/**
     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
     *
     * @param str 指定字符串
     * @param strs 需要检查的字符串数组
     * @return 是否匹配
     */
    public static boolean matches(String str, List<String> strs)
    {
    
    
        if (isEmpty(str) || isEmpty(strs))
        {
    
    
            return false;
        }
        for (String testStr : strs)
        {
    
    
            if (matches(str, testStr))
            {
    
    
                return true;
            }
        }
        return false;
    }

    /**
     * 查找指定字符串是否匹配指定字符串数组中的任意一个字符串
     *
     * @param str 指定字符串
     * @param strs 需要检查的字符串数组
     * @return 是否匹配
     */
    public static boolean matches(String str, String... strs)
    {
    
    
        if (isEmpty(str) || isEmpty(strs))
        {
    
    
            return false;
        }
        for (String testStr : strs)
        {
    
    
            if (matches(str, testStr))
            {
    
    
                return true;
            }
        }
        return false;
    }

    /**
     * 查找指定字符串是否匹配
     *
     * @param str 指定字符串
     * @param pattern 需要检查的字符串
     * @return 是否匹配
     */
    public static boolean matches(String str, String pattern)
    {
    
    
        if (isEmpty(pattern) || isEmpty(str))
        {
    
    
            return false;
        }

        pattern = pattern.replaceAll("\\s*", ""); // 替换空格
        int beginOffset = 0; // pattern截取开始位置
        int formerStarOffset = -1; // 前星号的偏移位置
        int latterStarOffset = -1; // 后星号的偏移位置

        String remainingURI = str;
        String prefixPattern = "";
        String suffixPattern = "";

        boolean result = false;
        do
        {
    
    
            formerStarOffset = indexOf(pattern, START, beginOffset);
            prefixPattern = substring(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length());

            // 匹配前缀Pattern
            result = remainingURI.contains(prefixPattern);
            // 已经没有星号,直接返回
            if (formerStarOffset == -1)
            {
    
    
                return result;
            }

            // 匹配失败,直接返回
            if (!result)
                return false;

            if (!isEmpty(prefixPattern))
            {
    
    
                remainingURI = substringAfter(str, prefixPattern);
            }

            // 匹配后缀Pattern
            latterStarOffset = indexOf(pattern, START, formerStarOffset + 1);
            suffixPattern = substring(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length());

            result = remainingURI.contains(suffixPattern);
            // 匹配失败,直接返回
            if (!result)
                return false;

            if (!isEmpty(suffixPattern))
            {
    
    
                remainingURI = substringAfter(str, suffixPattern);
            }

            // 移动指针
            beginOffset = latterStarOffset + 1;

        }
        while (!isEmpty(suffixPattern) && !isEmpty(remainingURI));

        return true;
    }

    @SuppressWarnings("unchecked")
    public static <T> T cast(Object obj)
    {
    
    
        return (T) obj;
    }


/**
     * * 判断一个字符串是否为空串
     *
     * @param str String
     * @return true:为空 false:非空
     */
    public static boolean isEmpty(String str)
    {
    
    
        return isNull(str) || NULLSTR.equals(str.trim());
    }

}

猜你喜欢

转载自blog.csdn.net/SHUKAI618/article/details/116719462