登录 免费注册

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

2019-12-21 阅读:4151
分类:技术前沿
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商城系统的二次开发

标签 :Java商城
发表时间: 2021-05-12

跨境电商服务的新思路——AI与大数据

发表时间: 2024-11-06

如何利用Java构建卓越的个性化购物商城系统用户体验

发表时间: 2023-11-27
推荐阅读

南钢鑫智链平台 | 供应链集采平台解决方案

发表时间:2024-01-06

java电商领域的技术专家Newway

发表时间:2023-04-13

“数”及大文旅,“链”推大湾区 | 朗尊携手广东电视台助推乡村振兴

发表时间:2023-10-16

传音商城 | 打造高效采购新生态,赋能全球员工与供应链

发表时间:2025-04-10

如何解决传统工业大众交易的问题?

发表时间:2025-03-07

咨询

电话

免费注册