详解Java Web如何限制访问的IP的两种方法

前一阵子因为在做项目时碰到了这个功能,现在好好总结一下,至于为什么要限制IP访问,我就不多说了。然后百度了一下,现在主要有两种方式去限制IP访问,第一种是最简单的方便的,第二种是通过过滤器来限制访问。下面我简单介绍一下第一种方式,着重介绍第二种。

第一种方式(Tomcat配置项配置允许或限制IP访问)

这种是最简单的快捷的,主要就涉及Tomcat的server.xml配置。

第一步:找到server.xml文件在哪,在Tomcat的目录下的conf文件夹下。
第二步:打开server.xml文件,找到Host节点,在其中加上:

<Valve className="org.apache.catalina.valves.RemoteAddrValve"
	allow="127.0.0.1"
	deny=""/>

其中:
className:表示java类名,必须是
org.apache.catalina.valves.RemoteHostValve或org.apache.catalina.valves.RemoteAddrValve;
allow:表示允许的IP,支持模糊(* )、正则,多个用,隔开;
deny:表示限制的IP,支持模糊(
*)、正则;多个用,隔开。
注:如果是限制某一个站点(网站)则在Context节点中添加。
第三步:重启Tomcat。

第二种方式(通过Filter过滤器来配置允许或限制IP访问)

(1)代码实现的思路
  通过增加配置文件properties,将允许访问的IP按一定规则配置进去;接下来再对配置文件(这里尚且叫做配置文件)进行加载;然后再对配置文件的格式要求通过正则进行校验;其次将配置的IP通过一个集合进行收集,可收集单条IP或一个IP的正则,因为我们这里需要用到模糊;最后对访问者的IP与集合中的进行比对,比对通过则正常访问,否则。反之。
  在配置文件中提供三种最常见的IP配置方式:

单个IP地址的配置,多个之间用逗号或分好隔开;
例如:192.168.1.50;127.0.0.1;IP地址区间方式的配置,多个区间用逗号或分好隔开;
例如:172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89通配符,多个用逗号或分好隔开。
例如:172.20.30.*

(2)具体实现代码
第一步:编写配置文件/Test/src/com/config/ipConfig.properties;

#单个IP地址的配置,多个之间用逗号或分好隔开
allowIP=192.168.1.50;127.0.0.1;

#IP地址区间方式的配置,多个区间用逗号或分好隔开
allowIPRange=172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89

#通配符,多个用逗号或分好隔开
allowIPWildcard=172.20.30.*;

第二步:新建Java类实现Filter;
第三步:在web.xml中配置过滤器;

<!-- 过滤器 -->

 <!-- ip过滤器,过滤所有请求地址 -->
 <filter>
 	<filter-name>IPFilter</filter-name>
 	<filter-class>com.filter.IpFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>IPFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 <!-- 结束过滤器 -->

第四步:我们需要声明一个全局变量List来存放允许访问的IP或正则式;

//声明的代码:
//用来存放允许访问的ip
private List<String> allowList = new ArrayList<String>();

第五步:需要对配置文件进行加载;在方法init中

//加载的代码:
//将文件转化成流
InputStream inputStream = IpFilter.class.getResourceAsStream("../config/ipConfig.properties");

Properties properties = new Properties();

//通过Properties对象实例加载流
properties.load(inputStream);

//获取三种配置方式的值
String allowIP = properties.getProperty("allowIP");
String allowIPRange = properties.getProperty("allowIPRange");
String allowIPWildcard = properties.getProperty("allowIPWildcard");

第六步:校验配置文件格式;在方法init中

//校验的部分代码
//如果为空,说明用户没添加该项,不做处理
if(allow == null || "".equals(allow.trim())) {
	return true;
} else {
	//在最后面没有,或;的给添上
	if(!allow.endsWith(";") && !allow.endsWith(",")) {
		allow += ";";
	}
	//如果匹配,则返回true
	if(pattern.matcher(allow).matches()) {
		return true;
	}
}

第七步:获取每种配置方式的IP;在方法init中

/*
 * 将每一种配置方法放置到allowList中
 */
//将第一种配置方法放到allowList中
if(null != allowIP && !"".equals(allowIP.trim())) {
	String[] allowIPs = allowIP.split(",|;");
	for(String ip : allowIPs) {
		allowList.add(ip);
	}
}

//将第二种配置方法放到allowList中
if(null != allowIPRange &&
		!"".equals(allowIPRange.trim())) {
	//先进行每一段的分割
	String[] allowIPRanges = allowIPRange.split(",|;");

	if(allowIPRanges.length > 0) {
		//对每一段进行遍历
		for(String allowRanges : allowIPRanges) {
			if(allowRanges != null &&
					!"".equals(allowRanges.trim())) {
				//对该段的ip进行解析
				String[] ips = allowRanges.split("-");
				if(ips.length > 0 && ips.length < 3) {
					String from = ips[0];//得到该段的起始ip
					String to = ips[1]; //得到该段的结束ip

					//获取该ip段地址的前三段,因为起始和结束的ip的前三段一样
					String share = from.substring(0, from.lastIndexOf(".")+1);

					//获取该ip段的起始ip的最后一段
					int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1,
														from.length()));
					//获取该ip段的结束ip的最后一段
					int end = Integer.parseInt(to.substring(to.lastIndexOf(".")+1,
														to.length()));
					for(int i=start; i<=end; i++) {
						String ip = share + String.valueOf(i);
						allowList.add(ip);
					}
				} else {
					throw new RuntimeException("配置文件有错,请检查!");
				}
			}

		}
	}

}

//将第三种配置方法放到allowList中
if(allowIPWildcard != null &&
		!"".equals(allowIPWildcard)) {
	//获取每个含通配符的ip地址
	String[] allowIPWildcards = allowIPWildcard.split(",|;");

	if(allowIPWildcards.length > 0) {
		for(String ip : allowIPWildcards) {
			if(ip.indexOf("*") != -1) {
				//对*进行替换
				ip = ip.replaceAll("\\*", "(25[0-5]|2[0-4]\\\\d|[0-1]\\\\d{2}|[1-9]?\\\\d)");

				allowList.add(ip);
			} else {
				throw new RuntimeException("配置文件有错,请检查!");
			}

		}

	}
}

第八步:IP比对,成功匹配就正常访问,反之则跳到错误页面。这个因为是在用户访问时才进行的步骤,需要在doFilter方法的编写。

//获取访问的IP地址
String remoteAddr = request.getRemoteAddr();
//System.out.println("===============" + remoteAddr);
//如果allowList为空,则认为没做限制,不为空则检查是否限制
if(allowList.size() == 0 || allowList == null) {
	filterChain.doFilter(request, response);
} else {
	Boolean flag = false; //访问标志,默认为false,限制访问
	//进行逐个检查
	for(String regex : allowList){
		if(remoteAddr.matches(regex)){
			//ip没被限制,正常访问
			filterChain.doFilter(request, response);
			flag = true; //置为true,表示不限制访问
			break;
		}
	}
	if(!flag) {
		//ip被限制,跳到指定页面
		request.getRequestDispatcher("WEB-INF/success/error.jsp").forward(request, response);
	}
}

附成功后截图:

附完整代码:

package com.filter;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 过滤器
 * 功能:对访问者IP进行限制访问
 * @author ouyang
 * @serial 20180728
 * @version 1.0
 */
public class IpFilter implements Filter{

	//用来存放允许访问的ip
	private List<String> allowList = new ArrayList<String>();

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		try {
			System.out.println("过滤器IpFilter开始初始化,功能:IP访问限制");
			initConfig();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {

		//获取访问的IP地址
		String remoteAddr = request.getRemoteAddr();
		//System.out.println("===============" + remoteAddr);
		//如果allowList为空,则认为没做限制,不为空则检查是否限制
		if(allowList.size() == 0 || allowList == null) {
			filterChain.doFilter(request, response);
		} else {
			Boolean flag = false; //访问标志,默认为false,限制访问
			//进行逐个检查
			for(String regex : allowList){
				if(remoteAddr.matches(regex)){
					//ip没被限制,正常访问
					filterChain.doFilter(request, response);
					flag = true; //置为true,表示不限制访问
					break;
				}
			}
			if(!flag) {
				//ip被限制,跳到指定页面
				request.getRequestDispatcher("WEB-INF/success/error.jsp").forward(request, response);
			}
		}

	}

	@Override
	public void destroy() {
		System.out.println("过滤器IpFilter结束。");
	}

	/**
	 * 对配置文件进行初始化并校验
	 * @author 欧阳
	 * @serialData 20180728
	 * @throws IOException
	 */
	public void initConfig() throws IOException {
		//将文件转化成流
		InputStream inputStream = IpFilter.class.getResourceAsStream("../config/ipConfig.properties");

		Properties properties = new Properties();

		//通过Properties对象实例加载流
		properties.load(inputStream);

		//获取三种配置方式的值
		String allowIP = properties.getProperty("allowIP");
		String allowIPRange = properties.getProperty("allowIPRange");
		String allowIPWildcard = properties.getProperty("allowIPWildcard");

		//校验,校验失败后抛出异常
		if(!validate(allowIP, allowIPRange, allowIPWildcard)) {
			throw new RuntimeException("配置文件有错,请检查!");
		}

		/*
		 * 将每一种配置方法放置到allowList中
		 */
		//将第一种配置方法放到allowList中
		if(null != allowIP && !"".equals(allowIP.trim())) {
			String[] allowIPs = allowIP.split(",|;");
			for(String ip : allowIPs) {
				allowList.add(ip);
			}
		}

		//将第二种配置方法放到allowList中
		if(null != allowIPRange &&
				!"".equals(allowIPRange.trim())) {
			//先进行每一段的分割
			String[] allowIPRanges = allowIPRange.split(",|;");

			if(allowIPRanges.length > 0) {
				//对每一段进行遍历
				for(String allowRanges : allowIPRanges) {
					if(allowRanges != null &&
							!"".equals(allowRanges.trim())) {
						//对该段的ip进行解析
						String[] ips = allowRanges.split("-");
						if(ips.length > 0 && ips.length < 3) {
							String from = ips[0];//得到该段的起始ip
							String to = ips[1]; //得到该段的结束ip

							//获取该ip段地址的前三段,因为起始和结束的ip的前三段一样
							String share = from.substring(0, from.lastIndexOf(".")+1);

							//获取该ip段的起始ip的最后一段
							int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1,
																from.length()));
							//获取该ip段的结束ip的最后一段
							int end = Integer.parseInt(to.substring(to.lastIndexOf(".")+1,
																to.length()));
							for(int i=start; i<=end; i++) {
								String ip = share + String.valueOf(i);
								allowList.add(ip);
							}
						} else {
							throw new RuntimeException("配置文件有错,请检查!");
						}
					}

				}
			}

		}

		//将第三种配置方法放到allowList中
		if(allowIPWildcard != null &&
				!"".equals(allowIPWildcard)) {
			//获取每个含通配符的ip地址
			String[] allowIPWildcards = allowIPWildcard.split(",|;");

			if(allowIPWildcards.length > 0) {
				for(String ip : allowIPWildcards) {
					if(ip.indexOf("*") != -1) {
						//对*进行替换
						ip = ip.replaceAll("\\*", "(25[0-5]|2[0-4]\\\\d|[0-1]\\\\d{2}|[1-9]?\\\\d)");

						allowList.add(ip);
					} else {
						throw new RuntimeException("配置文件有错,请检查!");
					}

				}

			}
		}

		//打印输出allowList
		for(String str : allowList) {
			System.out.println(str);
		}

	}

	/**
	 * 对配置文件进行校验
	 * @author ouyang
	 * @serialData 20180728
	 * @param allowIP
	 * @param allowIPRange
	 * @param allowIPWildcard
	 * @return
	 */
	public Boolean validate(String allowIP, String allowIPRange, String allowIPWildcard) {
		Boolean result = false;
		//IP地址每一段的正则
		String regx = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)";
		//整个ip的正则
		String ipRegx = regx + "\\." + regx + "\\."+ regx + "\\." + regx;

		//对第一种方式进行校验
		Pattern pattern = Pattern.compile("("+ipRegx+")|("+ipRegx+"(,|;))*");
		if(this.isNullorMatches(allowIP, pattern)){
			result = true; //匹配成功
		} else {
			result = false;
		}

		//对第二种方式进行校验
		pattern = Pattern.compile("("+ipRegx+")\\-("+ipRegx+")|" +
						"(("+ipRegx+")\\-("+ipRegx+")(,|;))*");
		if(this.isNullorMatches(allowIPRange, pattern)){
			result = true; //匹配成功
		} else {
			result = false;
		}

		//对第三种方式进行校验
		pattern = Pattern.compile("("+regx+"\\."+ regx+"\\."+regx+"\\."+ "\\*)|" +
						"("+regx+"\\."+regx+"\\."+regx+"\\."+ "\\*(,|;))*");
		if(this.isNullorMatches(allowIPWildcard, pattern)){
			result = true; //匹配成功
		} else {
			result = false;
		}

		return result;
	}

	/**
	 * 进行正则匹配
	 * @author 欧阳
	 * @serialData 20180728
	 * @param allow
	 * @return
	 */
	public Boolean isNullorMatches(String allow, Pattern pattern) {
		//如果为空,说明用户没添加该项,不做处理
		if(allow == null || "".equals(allow.trim())) {
			return true;
		} else {
			//在最后面没有,或;的给添上
			if(!allow.endsWith(";") && !allow.endsWith(",")) {
				allow += ";";
			}
			//如果匹配,则返回true
			if(pattern.matcher(allow).matches()) {
				return true;
			}
		}

		return false;
	}
}

到此这篇关于详解Java Web如何限制访问的IP的两种方法的文章就介绍到这了,更多相关Java 限制访问的IP内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java如何限制IP访问页面

    最近遇到一个需求,一个只能内网访问的网站,需要限制ip访问.就是网站内的部分文章只有白名单内的ip才能打开.因为是静态化的网站,所有文章都是静态html页面.所以首先想到的就是直接js获取访问者ip然后再判断是否在白名单内,不在白名单内就到没有权限页面. 但是JS获取内网Ip还是比较麻烦的,查到几个方法最后试了都不行. 记录下查到的几个方法和最后实现的方法. JS获取外网ip的方法: //最简单的获取外网ip的方法.可以直接用,但是没啥用.. <script src="http://pv.

  • Java 限制子类访问的方法分析

    本文实例讲述了Java 限制子类访问的方法.分享给大家供大家参考,具体如下: 一 点睛 有时候,父类想保护自己的"隐私",即使自己的成员被子类继承了,并不希望子类可以访问自己类中全部的属性或方法,这时,就需要将一些属性与方法隐藏起来,不让子类去使用.此时可在声明属性或方法时加上"private"关键字,表示私有访问权限,即除了声明该属性或方法所在类,其他外部类(包括子类)均无权访问. 二 实战--限制子类的访问 1 代码 class Person { // 在这里将

  • 详解Java Web如何限制访问的IP的两种方法

    前一阵子因为在做项目时碰到了这个功能,现在好好总结一下,至于为什么要限制IP访问,我就不多说了.然后百度了一下,现在主要有两种方式去限制IP访问,第一种是最简单的方便的,第二种是通过过滤器来限制访问.下面我简单介绍一下第一种方式,着重介绍第二种. 第一种方式(Tomcat配置项配置允许或限制IP访问) 这种是最简单的快捷的,主要就涉及Tomcat的server.xml配置. 第一步:找到server.xml文件在哪,在Tomcat的目录下的conf文件夹下. 第二步:打开server.xml文件

  • 详解eclipse将项目打包成jar文件的两种方法及问题解决方法

    第一种:利用eclipse中自带的export功能 第一种方法分两种情况先来看第一种情况:没有引用外部jar的项目打包 步骤一:右键点击项目选择导出(export),选择java>jar文件(不是选择可运行jar文件) 步骤二:选择你要导出的项目以及文件,指定文件导出路径.连续点击两个下一步后到第四步. 步骤三:选择主类. 按照以上步骤即可完成对一个不引用外部jar项目的打包. 第二种情况:没有引用外部jar的项目打包 当我们引用了外部jar后,使用eclipse自带的export打包略显繁琐.

  • 详解vue.js下引入百度地图jsApi的两种方法

    前言 今天有个项目需要用到百度地图,一般我们在移动端使用百度地图,都是直接通过这样的方式,直接引入百度地图的jsApi. <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=D9b45bc6f98deafc489e9ac1bc7f7612"></script> 这种方法的原理,就是直接给全局widow对象添加一个BMap对象,从而可以使我们

  • 详解Java redis中缓存穿透 缓存击穿 雪崩三种现象以及解决方法

    目录 前言 一.缓存穿透 二.缓存击穿 三.雪崩现象 总结 前言 本文主要阐述redis中的三种现象 1.缓存穿透 2.缓存击穿 3.雪崩现象 本文主要说明本人对三种情况的理解,如果需要知道redis基础请查看其他博客,加油! 一.缓存穿透 理解:何为缓存穿透,先要了解穿透,这样有助于区分穿透和击穿,穿透就类似于伤害一点一点的累计,最终打到穿透的目的,类似于射手,一下一下普通攻击,最终杀死对方,先上图 先来描述一下缓存穿透的过程: 1.由于我们取数据的原则是先查询redis上,如果redis上有

  • 详解JAVA生成将图片存入数据库的sql语句实现方法

    详解JAVA生成将图片存入数据库的sql语句实现方法 实现代码: 注释很清楚,不在重述~ public class Image2Hex { public static void main(String[] args) { try{ //存放图片的文件夹 File list = new File("d:/qmx"); File[] lists = list.listFiles(); String name; //生成的语句存放文件 PrintWriter pw = new PrintWr

  • 详解Java如何通过Socket实现查询IP

    目录 背景 使用示例 应用例子 应用服务器 获取客户端的IP地址 向客户端发送消息 测试应用程序 建立一个客户端应用程序 运行应用程序 在后台发生了什么 总结 在本文中,我们来学习下如何找到连接到服务器的客户端计算机的IP地址.我们将创建一个简单的客户端-服务器场景,让我们探索用于TCP/IP通信的java.net API. 背景 Java应用程序使用套接字在互联网上进行通信和发送数据.Java为客户端应用程序提供了java.net.Socket类. java.net.ServerSocket类

  • 详解向scrapy中的spider传递参数的几种方法(2种)

    有时需要根据项目的实际需求向spider传递参数以控制spider的行为,比如说,根据用户提交的url来控制spider爬取的网站.在这种情况下,可以使用两种方法向spider传递参数. 第一种方法,在命令行用crawl控制spider爬取的时候,加上-a选项,例如: scrapy crawl myspider -a category=electronics 然后在spider里这样写: import scrapy class MySpider(scrapy.Spider): name = 'm

  • C#访问命令行的两种方法

    本文实例讲述了C#访问命令行的两种方法.分享给大家供大家参考.具体如下: 方法1: // 参数:A B C using System; public class CommandLine { public static void Main(string[] args) { // Length 属性用于获取数组的长度. // 注意,Length 是只读属性: Console.WriteLine("Number of command line parameters = {0}", args.

  • java 在file的尾部添加数据的两种方法总结

    java 在file的尾部添加数据的两种方法总结 问题描述:   在文件的末尾追加内容 方法1:利用RandomAccessFile类  1.将randomAccessFile模式设置为rw  2将randomAccessFile移动(seek)到文件末尾  3追加数据  4关闭流 方法2:利用FileWriter类  1.将FileWriter构造方法第二个参数置为true.表示在尾部追加  2追加数据  3.关闭流 实现代码: package cn.com; import java.io.F

  • Java实现对象按照其属性排序的两种方法示例

    本文实例讲述了Java实现对象按照其属性排序的两种方法.分享给大家供大家参考,具体如下: 有时候需要对对象列表或数组进行排序,下面提供两种简单方式: 方法一:将要排序的对象类实现Comparable<>接口. 首先,创建学生类,我们将根据学生成绩对学生进行排序: /** * 学生类 */ class Student implements Comparable<Student>{ String name; int age; int score; public Student(Stri

随机推荐