返回首页
基于java过滤器实现web系统的IP访问控制
发表时间:2019-12-21 阅读:2389
Java商城
微信小程序商城
多用户商城
Legendshop的粉丝都清楚,目前主流的商城平台: 淘宝,京东, 唯品会等都是和legendshop 一样采用java。今天我们Legendshop的开发哥给大家带来了JAVA技术干货。

一.使用场景

一般情况下,我们设计web系统都会分别设计前台和后台,前台供普通用户访问,给普通用户提供服务.然后后台给系统管理员使用,用于管理维护前台的数据,以及对一些环境的参数配置.对于后台管理一般都是只给公司内部的员工进行访问,所以我们一般要通过IP来限制访问,实现指定的人群才能够访问后台.


.实现原理

1.     把允许访问的IP地址,配置到properties文件里.

2.     编写过滤器,在过滤器的init方法里读取保存IP白名单的properties文件,把配置的IP地址解析出来,存放到一个List集合中.

3.     在过滤器的doFilter()方法内,获取访问用户的IP地址,然后将用户IPList集合中的白名单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 ListallowRegexList = new ArrayList();


@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() {


}

}


.备注

本文比较不好理解的就是对第三种IP配置方式的解析,我的程序是把第三中配置的IP白名单解析为正则表达式的,比如用户配置的是192.168.1.,我并不是把它解析为192.168.1.0192.168.1.255256IP地址,然后放到List集合中,而是吧192.168.1.解析为一条正则表达式192.168.1.(1\d{1,2}|2[0-4]\d|25[0-5]|\d{1,2}) 这条正则表达式可以匹配192.168.1.0192.168.1.255256IP地址,这样就大大减少了程序循环的次数,提高了程序的性能.但由于我这里存放的是正则,所以我干脆就把我前面定义的那个存放白名单的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; }

文章来源:关开发
【朗尊软件】是中国领先的专业电商平台提供商,秉承着“专业塑造传奇,用心成就电商”的理念, 专注于为用户提供一体化的电商解决方案及服务,搭建垂直行业垂直电商一站式营销管理工具。目前拥有自主研发的电子商务平台产品:SAAS云平台、微商城小程序、云商城、云小店、代理商平台、B2B2C商城、B2B大宗交易平台、跨境电商服务、大数据平台搭建、微服务架构等产品、各种定制商城及解决方案。
网站声明:以上内容为朗尊软件官方网站的原创文章,如需转载,请注明出处,谢谢合作!
上一篇: Legendshop B2B2B多用户订货系统功能列表
下一篇: Java的实现二级域名访问卖家首页 - 朗尊软件,企业级电商平台提供商
相关文章
区块链技术热了这么久,你还没找到入门方法? - 朗尊软件,企业级电商平台提供商
《信息系统安全等级保护基本要求》之六 - 朗尊软件,企业级电商平台提供商
基于java过滤器实现web系统的IP访问控制
开源商城系统介绍企业写开源多用户商城 - 朗尊软件,企业级电商平台提供商
供应链金融浅析 - 朗尊软件,企业级电商平台提供商
电商头条新闻
1
工业行业 | 工业产品B2B跨境电商解决方案
2
私域电商如何赶上智能热潮?
3
三一全球购 | B2B2C电商平台+员工福利平台的定制解决方案
4
跨境电商 | B2B2C跨境电商系统解决方案
5
社群团购系统——社区流量与社交电商融合
热门标签
小羊直播
供应链
电商系统
Java商城
电商平台
B2B商城
跨境电商
商城平台
新零售系统
云商城系统
B2B2C商城系统
多用户商城
微服务商城
供应链商城
商城系统
电商直播系统
私域电商
大宗交易平台
数字化转型
直播供应链
全渠道零售
O2O商城系统
java开源商城
SAAS云平台
B2C商城系统
SaaS系统
生鲜电商
用户标签
APP
S2B
MRO平台
微信小程序商城
移动商城
社区电商
营销活动
新零售电商
分销系统
门店管理
分销体系
社交电商
直播电商
数字化
客服系统
社群电商
引爆流量
供应链金融
员工福利平台
工会福利商城
企业智慧采购平台
机械设备
抖音电商
数智化
数字化
区块链
S2B2C
B2B2B
订单融资
数字中台
VUE
用户标签
仓单融资
大数据
应收账款
集采代采
医药电商
推荐阅读
公告:【微信小程序备案】9月1日起,微信小程序需完成备案才可上架!
工业行业 | 工业产品B2B跨境电商解决方案
私域电商如何赶上智能热潮?
三一全球购 | B2B2C电商平台+员工福利平台的定制解决方案
跨境电商 | B2B2C跨境电商系统解决方案