詳解Java Web如何限制訪問的IP的兩種方法
前一陣子因為在做項目時碰到了這個功能,現(xiàn)在好好總結(jié)一下,至于為什么要限制IP訪問,我就不多說了。然后百度了一下,現(xiàn)在主要有兩種方式去限制IP訪問,第一種是最簡單的方便的,第二種是通過過濾器來限制訪問。下面我簡單介紹一下第一種方式,著重介紹第二種。
第一種方式(Tomcat配置項配置允許或限制IP訪問)
這種是最簡單的快捷的,主要就涉及Tomcat的server.xml配置。
第一步:找到server.xml文件在哪,在Tomcat的目錄下的conf文件夾下。
第二步:打開server.xml文件,找到Host節(jié)點,在其中加上:
<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,支持模糊( *)、正則;多個用,隔開。
注:如果是限制某一個站點(網(wǎng)站)則在Context節(jié)點中添加。
第三步:重啟Tomcat。
第二種方式(通過Filter過濾器來配置允許或限制IP訪問)
(1)代碼實現(xiàn)的思路
通過增加配置文件properties,將允許訪問的IP按一定規(guī)則配置進(jìn)去;接下來再對配置文件(這里尚且叫做配置文件)進(jìn)行加載;然后再對配置文件的格式要求通過正則進(jìn)行校驗;其次將配置的IP通過一個集合進(jìn)行收集,可收集單條IP或一個IP的正則,因為我們這里需要用到模糊;最后對訪問者的IP與集合中的進(jìn)行比對,比對通過則正常訪問,否則。反之。
在配置文件中提供三種最常見的IP配置方式:
單個IP地址的配置,多個之間用逗號或分好隔開;
例如:192.168.1.50;127.0.0.1;IP地址區(qū)間方式的配置,多個區(qū)間用逗號或分好隔開;
例如:172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89通配符,多個用逗號或分好隔開。
例如:172.20.30.*
(2)具體實現(xiàn)代碼
第一步:編寫配置文件/Test/src/com/config/ipConfig.properties;
#單個IP地址的配置,多個之間用逗號或分好隔開 allowIP=192.168.1.50;127.0.0.1; #IP地址區(qū)間方式的配置,多個區(qū)間用逗號或分好隔開 allowIPRange=172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89 #通配符,多個用逗號或分好隔開 allowIPWildcard=172.20.30.*;
第二步:新建Java類實現(xiàn)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> <!-- 結(jié)束過濾器 -->
第四步:我們需要聲明一個全局變量List來存放允許訪問的IP或正則式;
//聲明的代碼: //用來存放允許訪問的ip private List<String> allowList = new ArrayList<String>();
第五步:需要對配置文件進(jìn)行加載;在方法init中
//加載的代碼:
//將文件轉(zhuǎn)化成流
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())) {
//先進(jìn)行每一段的分割
String[] allowIPRanges = allowIPRange.split(",|;");
if(allowIPRanges.length > 0) {
//對每一段進(jìn)行遍歷
for(String allowRanges : allowIPRanges) {
if(allowRanges != null &&
!"".equals(allowRanges.trim())) {
//對該段的ip進(jìn)行解析
String[] ips = allowRanges.split("-");
if(ips.length > 0 && ips.length < 3) {
String from = ips[0];//得到該段的起始ip
String to = ips[1]; //得到該段的結(jié)束ip
//獲取該ip段地址的前三段,因為起始和結(jié)束的ip的前三段一樣
String share = from.substring(0, from.lastIndexOf(".")+1);
//獲取該ip段的起始ip的最后一段
int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1,
from.length()));
//獲取該ip段的結(jié)束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) {
//對*進(jìn)行替換
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比對,成功匹配就正常訪問,反之則跳到錯誤頁面。這個因為是在用戶訪問時才進(jìn)行的步驟,需要在doFilter方法的編寫。
//獲取訪問的IP地址
String remoteAddr = request.getRemoteAddr();
//System.out.println("===============" + remoteAddr);
//如果allowList為空,則認(rèn)為沒做限制,不為空則檢查是否限制
if(allowList.size() == 0 || allowList == null) {
filterChain.doFilter(request, response);
} else {
Boolean flag = false; //訪問標(biāo)志,默認(rèn)為false,限制訪問
//進(jìn)行逐個檢查
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進(jìn)行限制訪問
* @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為空,則認(rèn)為沒做限制,不為空則檢查是否限制
if(allowList.size() == 0 || allowList == null) {
filterChain.doFilter(request, response);
} else {
Boolean flag = false; //訪問標(biāo)志,默認(rèn)為false,限制訪問
//進(jìn)行逐個檢查
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結(jié)束。");
}
/**
* 對配置文件進(jìn)行初始化并校驗
* @author 歐陽
* @serialData 20180728
* @throws IOException
*/
public void initConfig() throws IOException {
//將文件轉(zhuǎn)化成流
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())) {
//先進(jìn)行每一段的分割
String[] allowIPRanges = allowIPRange.split(",|;");
if(allowIPRanges.length > 0) {
//對每一段進(jìn)行遍歷
for(String allowRanges : allowIPRanges) {
if(allowRanges != null &&
!"".equals(allowRanges.trim())) {
//對該段的ip進(jìn)行解析
String[] ips = allowRanges.split("-");
if(ips.length > 0 && ips.length < 3) {
String from = ips[0];//得到該段的起始ip
String to = ips[1]; //得到該段的結(jié)束ip
//獲取該ip段地址的前三段,因為起始和結(jié)束的ip的前三段一樣
String share = from.substring(0, from.lastIndexOf(".")+1);
//獲取該ip段的起始ip的最后一段
int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1,
from.length()));
//獲取該ip段的結(jié)束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) {
//對*進(jìn)行替換
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);
}
}
/**
* 對配置文件進(jìn)行校驗
* @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;
//對第一種方式進(jìn)行校驗
Pattern pattern = Pattern.compile("("+ipRegx+")|("+ipRegx+"(,|;))*");
if(this.isNullorMatches(allowIP, pattern)){
result = true; //匹配成功
} else {
result = false;
}
//對第二種方式進(jìn)行校驗
pattern = Pattern.compile("("+ipRegx+")\\-("+ipRegx+")|" +
"(("+ipRegx+")\\-("+ipRegx+")(,|;))*");
if(this.isNullorMatches(allowIPRange, pattern)){
result = true; //匹配成功
} else {
result = false;
}
//對第三種方式進(jìn)行校驗
pattern = Pattern.compile("("+regx+"\\."+ regx+"\\."+regx+"\\."+ "\\*)|" +
"("+regx+"\\."+regx+"\\."+regx+"\\."+ "\\*(,|;))*");
if(this.isNullorMatches(allowIPWildcard, pattern)){
result = true; //匹配成功
} else {
result = false;
}
return result;
}
/**
* 進(jìn)行正則匹配
* @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;
}
}
到此這篇關(guān)于詳解Java Web如何限制訪問的IP的兩種方法的文章就介紹到這了,更多相關(guān)Java 限制訪問的IP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
說一說java關(guān)鍵字final和transient
這篇文章主要和大家說一說java關(guān)鍵字final和transient,感興趣的小伙伴們可以參考一下2016-06-06
Java?Web項目中解決中文亂碼方法總結(jié)(三種最新方法)
這篇文章主要介紹了Java?Web項目中解決中文亂碼方法總結(jié),本文給大家分享三種最新解決方法,需要的朋友可以參考下2022-06-06
Java處理時間格式CST和GMT轉(zhuǎn)換方法示例
這篇文章主要給大家介紹了關(guān)于Java處理時間格式CST和GMT轉(zhuǎn)換方法的相關(guān)資料,相信很多小伙伴在時間格式轉(zhuǎn)換的時候非常頭疼,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09

