基于java过滤器实现web系统的IP访问控制

一.使用场景 
  一般情况下,我们设计web系统都会分别设计前台和后台,前台供普通用户访问,给普通用户提供服务.然后后台给系统管理员使用,用于管理维护前台的数据,以及对一些环境的参数配置.对于后台管理一般都是只给公司内部的员工进行访问,所以我们一般要通过IP来限制访问,实现指定的人群才能够访问后台. 
二.实现原理 
1. 把允许访问的IP地址,配置到properties文件里. 
2. 编写过滤器,在过滤器的init方法里读取保存IP白名单的properties文件,把配置的IP地址解析出来,存放到一个List集合中. 
3. 在过滤器的doFilter()方法内,获取访问用户的IP地址,然后将用户IP与List集合中的白名单IP列表逐个匹对,一旦有匹配就放行请求;如果都不匹配,则跳转到拒绝访问页面提示用户. 
三.代码实现 
1. IP白名单的配置 
 一般我们要提供三种配置IP白名单的方式 
 1). 单个IP地址的配置,多个之间用逗号或分好隔开 
 2). IP地址区间方式的配置,多个区间用逗号或分好隔开,如192.168.1.0-192.168.1.10;192.168.1.20-192.168.1.50 
 3). 通配符,多个用逗号或分好隔开,如192.168.0.* 
示例如下: 
#单个IP地址的配置,多个之间用逗号或分好隔开 
allowIP=192.168.0.105;192.168.0.108;127.0.0.1 

#IP地址区间方式的配置,多个区间用逗号或分好隔开 
allowIPRange=192.168.0.10-192.168.0.20;192.168.0.100-192.168.0.110 

#通配符,多个用逗号或分好隔开 
allowIPWildcard=192.168.0.*; 
1. 过滤器的编写 
package com.legendshop.filter; 
import java.io.FileInputStream; 
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; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import com.legendshop.exception.IPAccessException; 
import com.legendshop.exception.IPFormatException; 

public class IPFilter implements Filter { 
//用来存放初始化后的IP白名单列表对应的正则表达式 
private List<String> allowRegexList = new ArrayList<String>(); 

@Override 
public void init(FilterConfig config) throws ServletException { 
try { 
//在过滤器初始化的时候初始化白名单列表 
initAllowList(); 
} catch (IOException e) { 
e.printStackTrace(); 



public void initAllowList() throws IOException{ 
//读取配置文件,并加载到Properties集合中 
InputStream inStream = new FileInputStream("ipFilter.properties"); 
Properties prop = new Properties(); 
prop.load(inStream); 

//分别获取三种配置方式配置的IP 
String allowIP = prop.getProperty("allowIP"); 
String allowIPRange = prop.getProperty("allowIPRange"); 
String allowIPWildcard = prop.getProperty("allowIPWildcard"); 

//对用户配置的三种方式的IP白名单进行格式校验 
if(!validate(allowIP, allowIPRange, allowIPWildcard)){ 
throw new RuntimeException("IP白名单格式定义异常!"); 


//将第一种方式配置的ip地址解析出来,添加到存放IP白名单集合 
if(null != allowIP && !allowIP.trim().equals("")){ 
String[] address = allowIP.split(",|;"); 

if(null != address && address.length > 0){ 
for(String ip : address){ 
allowRegexList.add(ip); 




//将第二种方式配置的ip地址解析出来,添加到存放IP白名单集合 
if(null != allowIPRange && !allowIPRange.trim().equals("")){ 
String[] addressRanges = allowIPRange.split(",|;"); 

if(null != addressRanges && addressRanges.length > 0){ 
for(String addrRange : addressRanges){ 
String[] addrParts = addrRange.split("-"); 

if(null != addrParts && addrParts.length >0 && addrParts.length <= 2){ 
String from = addrParts[0]; 
String to = addrParts[1]; 
String prefix = from.substring(0, from.lastIndexOf(".")+1); 

int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1,from.length())); 
int end = Integer.parseInt(to.substring(to.lastIndexOf(".")+1,to.length())); 

for(int i = start;i <= end;i++){ 
allowRegexList.add(prefix+i); 


}else{ 
throw new RuntimeException("IP列表格式定义异常!"); 





//将第三种方式配置的ip地址解析为一条一条的正则表达式,添加到存放IP白名单集合,如对此处不明白可以先看后面的备注 
if(null != allowIPWildcard && !allowIPWildcard.trim().equals("")){ 
String[] address = allowIPWildcard.split(",|;"); 

if(null != address && address.length > 0){ 
for(String addr : address){ 
if(addr.indexOf("*") != -1){ 
//将*,替换成匹配单端ip地址的正则表达式 
addr = addr.replaceAll("\\*", "(1\\\\d{1,2}|2[0-4]\\\\d|25[0-5]|\\\\d{1,2})"); 
addr = addr.replaceAll("\\.", "\\\\.");//对.进行转义 
allowRegexList.add(addr); 
}else{ 
throw new RuntimeException("IP白名单格式定义异常!"); 






public boolean validate(String allowIP,String allowIPRange,String allowIPWildcard){ 

//匹配IP地址每一段的正则 
String regx = "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})"; 
//把四段用点连接起来,那就是匹配整个ip地址的表达式 
String ipRegx = regx + "\\." + regx + "\\."+ regx + "\\." + regx; 

//校验第一种配置方式配置的IP白名单格式是否正确 
Pattern pattern = Pattern.compile("("+ipRegx+")|("+ipRegx+"(,|;))*"); 
if(!this.validate(allowIP, pattern)){ 
return false; 


//校验第二种配置方式配置的的IP白名单格式是否正确 
pattern = Pattern.compile("("+ipRegx+")\\-("+ipRegx+")|"+ "(("+ipRegx+")\\-("+ipRegx+")(,|;))*"); 
if(!this.validate(allowIPRange, pattern)){ 
return false; 


//校验第三种配置方式配置的的IP白名单格式是否正确 
pattern = Pattern.compile("("+regx+"\\."+ regx+"\\."+regx+"\\."+ "\\*)|"+"("+regx+"\\."+regx+"\\."+regx+"\\."+ "\\*(,|;))*"); 
if(!this.validate(allowIPWildcard, pattern)){ 
return false; 

return true; 


//校验用户配置的ip列表格式是否正确 
public boolean validate(String allowIP,Pattern pattern){ 
//如果为空则不做处理 
if(null != allowIP && !allowIP.trim().equals("")){ 
StringBuilder sb = new StringBuilder(allowIP); 

//如果用户配置的IP配置了多个,但没有以分号结尾,这里就给它加上分号 
if(!allowIP.endsWith(";")){ 
sb.append(";"); 

//如果不匹配 
if(!pattern.matcher(sb).matches()){ 
return false; 


return true; 


@Override 
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) 
throws IOException, ServletException { 
HttpServletRequest request = (HttpServletRequest) req; 
HttpServletResponse response = (HttpServletResponse) resp; 

//1.获取访问者的IP地址 
String remoteAddr = request.getRemoteAddr(); 

if(null == remoteAddr || remoteAddr.trim().equals("")){ 
throw new RuntimeException("IP地址为空,拒绝访问!"); 


//如果白名单为空,则认为没做限制,放行 
if(null == allowRegexList || allowRegexList.size() == 0){ 
filterChain.doFilter(request, response); 
return; 


//检查用户IP是否在白名单 
if(checkIp(remoteAddr)){ 
filterChain.doFilter(request, response); 
return; 
}else{ 
throw new RuntimeException("您的IP:"+remoteAddr+",不在白名单中,拒绝访问!"); 



//检查用户IP是否在白名单 
public boolean checkIp(String remoteAddr){ 
for(String regex : allowRegexList){ 
if(remoteAddr.matches(regex)){ 
return true; 


return false; 


@Override 
public void destroy() { 




更多信息,请关注http://www.legendshop.cn 
三.备注 
  本文比较不好理解的就是对第三种IP配置方式的解析,我的程序是把第三中配置的IP白名单解析为正则表达式的,比如用户配置的是192.168.1.,我并不是把它解析为192.168.1.0到192.168.1.255的256个IP地址,然后放到List集合中,而是吧192.168.1.解析为一条正则表达式192.168.1.(1\d{1,2}|2[0-4]\d|25[0-5]|\d{1,2}) 这条正则表达式可以匹配192.168.1.0到192.168.1.255的256个IP地址,这样就大大减少了程序循环的次数,提高了程序的性能.但由于我这里存放的是正则,所以我干脆就把我前面定义的那个存放白名单的List集合理解为,它里面存放的每一条都是正则,匹配白名单的正则.无论他是一个IP地址,如192.168.1.1我也当它是正则.所以我上面是这样校验用户IP是否在白名单中: 

//检查用户IP是否在白名单 public boolean checkIp(String remoteAddr){ //把白名单列表中的每一条都当成正则来匹配 for(String regex : allowRegexList){ if(remoteAddr.matches(regex)){ return true; } } return false; } 

原文链接:http://www.bijishequ.com/detail/410522?p=


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值