登录访问时获取IP并校验(Springsecurity )

登录访问时获取IP并校验(Springsecurity )

一、简述

因公司要求,针对项目进行ip限制,以往只是记录登录ip。所以此功能相对简单。

二、获取IP

获取IP有两种方式:1、自定义ip工具类。2、security获取。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

public class IPUtils {

	private static final String UNKNOWN = "unknown";

	protected IPUtils() {

	}

	/**
	 * 获取IP地址 使用 Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
	 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非
	 * unknown的有效IP字符串,则为真实IP地址
	 */
	public static String getClientIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("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 = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Real-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		// log.info("获取客户端ip: " + ip);
		return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
	}
	/**
	 * 判断是否为内网
	 * @param ipAddress
	 * @return
	 */
	public static boolean isInnerIP(String ipAddress) {
		boolean isInnerIp = false;
		if (ipAddress.indexOf(",") != -1) {
			ipAddress = ipAddress.split(",")[0];
		}
		ipAddress = ipAddress.replaceAll(",", ".").replaceAll(" ", "");
		long ipNum = getIpNum(ipAddress);
		/**
		 * 私有IP:
		 * A类 10.0.0.0-10.255.255.255 
		 * B类  172.16.0.0-172.31.255.255 
		 * C类 192.168.0.0-192.168.255.255
			当然,还有127这个网段是环回地址
		 **/
		long aBegin = getIpNum("10.0.0.0");
		long aEnd = getIpNum("10.255.255.255");
		long bBegin = getIpNum("172.16.0.0");
		long bEnd = getIpNum("172.31.255.255");
		long cBegin = getIpNum("192.168.0.0");
		long cEnd = getIpNum("192.168.255.255");
		isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)
				|| ipAddress.equals("127.0.0.1");
		return isInnerIp;
	}

	private static long getIpNum(String ipAddress) {
		String[] ip = ipAddress.split("\\.");
		long a = Integer.parseInt(ip[0]);
		long b = Integer.parseInt(ip[1]);
		long c = Integer.parseInt(ip[2]);
		long d = Integer.parseInt(ip[3]);

		long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
		return ipNum;
	}

	private static boolean isInner(long userIp, long begin, long end) {
		return (userIp >= begin) && (userIp <= end);
	}
	/**
	 * 此方法调用百度AIP来查询IP所在地域(YYR)
	 * @param strIP(传入的IP地址)
	 * @return
	 */
	public static String getAddressByIP(String strIP) {
        try {
            URL url = new URL("http://api.map.baidu.com/location/ip?ak=F454f8a5efe5e577997931cc01de3974&ip="+strIP);
            URLConnection conn = url.openConnection();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String line = null;
            StringBuffer result = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            reader.close();
            String ipAddr = result.toString();
            try {
                JSONObject obj1= JSON.parseObject(ipAddr);
                if("0".equals(obj1.get("status").toString())){
                    JSONObject obj2= JSON.parseObject(obj1.get("content").toString());
                    JSONObject obj3= JSON.parseObject(obj2.get("address_detail").toString());
                    return obj3.get("province").toString()+obj3.get("city").toString();
                }else{
                    return "读取失败";
                }
            } catch (JSONException e) {
                e.printStackTrace();
                return "读取失败";
            }

        } catch (IOException e) {
            return "读取失败";
        }
    }
	
    public static String getAddress(String ip) {
    	String loginAddress = null;
    	try {
    		if (ip.indexOf(",") != -1) {
            	ip = ip.split(",")[0];
    		}
            
            if("127.0.0.1".equals(ip) || isInnerIP(ip)) {
    				loginAddress = "局域网";
            }else{
            	loginAddress = getAddressByIP(ip);
                if("读取失败".equals(loginAddress)) {
                	loginAddress = null;
                }
            }
            return loginAddress;
		} catch (Exception e) {
			return null;
		}
        
	}
}

在自定义的登录部分MyAuthenticationProvider 直接使用以下代码即可。

 WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
 String userIp = details.getRemoteAddress();

三、过滤IP

可以直接在Security的配置类中直接限制,指定ip时使用X.X.X.X ,若是ip段可是采用X.X.X.X/Y

//多个
http.authorizeRequests() 
     .antMatchers("/api/**", "/info") 
     .access("hasIpAddress('X.X.X.X') or hasIpAddress('Y.Y.Y.Y')") 
//单个
http.authorizeRequests()
   .antMatchers("/api/**", "/info").hasIpAddress("127.0.0.0/16")

自定义校验时,对访问ip的限制可以配置ip段,

public static boolean isInRange(String ip, String cidr) {
		String[] ips = ip.split("\\.");

		int ipAddr = (Integer.parseInt(ips[0]) << 24) | (Integer.parseInt(ips[1]) << 16) | (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
		int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
		int mask = 0xFFFFFFFF << (32 - type);

		String cidrIp = cidr.replaceAll("/.*", "");
		String[] cidrIps = cidrIp.split("\\.");

		int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24) | (Integer.parseInt(cidrIps[1]) << 16) | (Integer.parseInt(cidrIps[2]) << 8) | Integer.parseInt(cidrIps[3]);

		return (ipAddr & mask) == (cidrIpAddr & mask);
	}

在数据库或其他地方保存指定的多个ip,使用lamda或者for处理。

List<String> list = new ArrayList<String>();
list.add("127.0.0.1");
list.add("127.0.0.2");
list.add("127.0.0.4");

String ip = "127.0.0.6";
boolean bString =  list.stream().anyMatch(p -> p.equals(ip));

也可以针对用指定固定ip,查询用户数据直接比较即可。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值