詳解Java Web如何限制訪問(wèn)的IP的兩種方法
前一陣子因?yàn)樵谧鲰?xiàng)目時(shí)碰到了這個(gè)功能,現(xiàn)在好好總結(jié)一下,至于為什么要限制IP訪問(wèn),我就不多說(shuō)了。然后百度了一下,現(xiàn)在主要有兩種方式去限制IP訪問(wèn),第一種是最簡(jiǎn)單的方便的,第二種是通過(guò)過(guò)濾器來(lái)限制訪問(wèn)。下面我簡(jiǎn)單介紹一下第一種方式,著重介紹第二種。
第一種方式(Tomcat配置項(xiàng)配置允許或限制IP訪問(wèn))
這種是最簡(jiǎn)單的快捷的,主要就涉及Tomcat的server.xml配置。
第一步:找到server.xml文件在哪,在Tomcat的目錄下的conf文件夾下。
第二步:打開(kāi)server.xml文件,找到Host節(jié)點(diǎn),在其中加上:
<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,支持模糊(* )、正則,多個(gè)用,隔開(kāi);
deny:表示限制的IP,支持模糊( *)、正則;多個(gè)用,隔開(kāi)。
注:如果是限制某一個(gè)站點(diǎn)(網(wǎng)站)則在Context節(jié)點(diǎn)中添加。
第三步:重啟Tomcat。
第二種方式(通過(guò)Filter過(guò)濾器來(lái)配置允許或限制IP訪問(wèn))
(1)代碼實(shí)現(xiàn)的思路
通過(guò)增加配置文件properties,將允許訪問(wèn)的IP按一定規(guī)則配置進(jìn)去;接下來(lái)再對(duì)配置文件(這里尚且叫做配置文件)進(jìn)行加載;然后再對(duì)配置文件的格式要求通過(guò)正則進(jìn)行校驗(yàn);其次將配置的IP通過(guò)一個(gè)集合進(jìn)行收集,可收集單條IP或一個(gè)IP的正則,因?yàn)槲覀冞@里需要用到模糊;最后對(duì)訪問(wèn)者的IP與集合中的進(jìn)行比對(duì),比對(duì)通過(guò)則正常訪問(wèn),否則。反之。
在配置文件中提供三種最常見(jiàn)的IP配置方式:
單個(gè)IP地址的配置,多個(gè)之間用逗號(hào)或分好隔開(kāi);
例如:192.168.1.50;127.0.0.1;IP地址區(qū)間方式的配置,多個(gè)區(qū)間用逗號(hào)或分好隔開(kāi);
例如:172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89通配符,多個(gè)用逗號(hào)或分好隔開(kāi)。
例如:172.20.30.*
(2)具體實(shí)現(xiàn)代碼
第一步:編寫(xiě)配置文件/Test/src/com/config/ipConfig.properties;
#單個(gè)IP地址的配置,多個(gè)之間用逗號(hào)或分好隔開(kāi) allowIP=192.168.1.50;127.0.0.1; #IP地址區(qū)間方式的配置,多個(gè)區(qū)間用逗號(hào)或分好隔開(kāi) allowIPRange=172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89 #通配符,多個(gè)用逗號(hào)或分好隔開(kāi) allowIPWildcard=172.20.30.*;
第二步:新建Java類實(shí)現(xiàn)Filter;
第三步:在web.xml中配置過(guò)濾器;
<!-- 過(guò)濾器 --> <!-- ip過(guò)濾器,過(guò)濾所有請(qǐng)求地址 --> <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é)束過(guò)濾器 -->
第四步:我們需要聲明一個(gè)全局變量List來(lái)存放允許訪問(wèn)的IP或正則式;
//聲明的代碼: //用來(lái)存放允許訪問(wèn)的ip private List<String> allowList = new ArrayList<String>();
第五步:需要對(duì)配置文件進(jìn)行加載;在方法init中
//加載的代碼: //將文件轉(zhuǎn)化成流 InputStream inputStream = IpFilter.class.getResourceAsStream("../config/ipConfig.properties"); Properties properties = new Properties(); //通過(guò)Properties對(duì)象實(shí)例加載流 properties.load(inputStream); //獲取三種配置方式的值 String allowIP = properties.getProperty("allowIP"); String allowIPRange = properties.getProperty("allowIPRange"); String allowIPWildcard = properties.getProperty("allowIPWildcard");
第六步:校驗(yàn)配置文件格式;在方法init中
//校驗(yàn)的部分代碼 //如果為空,說(shuō)明用戶沒(méi)添加該項(xiàng),不做處理 if(allow == null || "".equals(allow.trim())) { return true; } else { //在最后面沒(méi)有,或;的給添上 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) { //對(duì)每一段進(jìn)行遍歷 for(String allowRanges : allowIPRanges) { if(allowRanges != null && !"".equals(allowRanges.trim())) { //對(duì)該段的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段地址的前三段,因?yàn)槠鹗己徒Y(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("配置文件有錯(cuò),請(qǐng)檢查!"); } } } } } //將第三種配置方法放到allowList中 if(allowIPWildcard != null && !"".equals(allowIPWildcard)) { //獲取每個(gè)含通配符的ip地址 String[] allowIPWildcards = allowIPWildcard.split(",|;"); if(allowIPWildcards.length > 0) { for(String ip : allowIPWildcards) { if(ip.indexOf("*") != -1) { //對(duì)*進(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("配置文件有錯(cuò),請(qǐng)檢查!"); } } } }
第八步:IP比對(duì),成功匹配就正常訪問(wèn),反之則跳到錯(cuò)誤頁(yè)面。這個(gè)因?yàn)槭窃谟脩粼L問(wèn)時(shí)才進(jìn)行的步驟,需要在doFilter方法的編寫(xiě)。
//獲取訪問(wèn)的IP地址 String remoteAddr = request.getRemoteAddr(); //System.out.println("===============" + remoteAddr); //如果allowList為空,則認(rèn)為沒(méi)做限制,不為空則檢查是否限制 if(allowList.size() == 0 || allowList == null) { filterChain.doFilter(request, response); } else { Boolean flag = false; //訪問(wèn)標(biāo)志,默認(rèn)為false,限制訪問(wèn) //進(jìn)行逐個(gè)檢查 for(String regex : allowList){ if(remoteAddr.matches(regex)){ //ip沒(méi)被限制,正常訪問(wèn) filterChain.doFilter(request, response); flag = true; //置為true,表示不限制訪問(wèn) break; } } if(!flag) { //ip被限制,跳到指定頁(yè)面 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; /** * 過(guò)濾器 * 功能:對(duì)訪問(wèn)者IP進(jìn)行限制訪問(wèn) * @author ouyang * @serial 20180728 * @version 1.0 */ public class IpFilter implements Filter{ //用來(lái)存放允許訪問(wèn)的ip private List<String> allowList = new ArrayList<String>(); @Override public void init(FilterConfig arg0) throws ServletException { try { System.out.println("過(guò)濾器IpFilter開(kāi)始初始化,功能:IP訪問(wèn)限制"); initConfig(); } catch (IOException e) { e.printStackTrace(); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { //獲取訪問(wèn)的IP地址 String remoteAddr = request.getRemoteAddr(); //System.out.println("===============" + remoteAddr); //如果allowList為空,則認(rèn)為沒(méi)做限制,不為空則檢查是否限制 if(allowList.size() == 0 || allowList == null) { filterChain.doFilter(request, response); } else { Boolean flag = false; //訪問(wèn)標(biāo)志,默認(rèn)為false,限制訪問(wèn) //進(jìn)行逐個(gè)檢查 for(String regex : allowList){ if(remoteAddr.matches(regex)){ //ip沒(méi)被限制,正常訪問(wèn) filterChain.doFilter(request, response); flag = true; //置為true,表示不限制訪問(wèn) break; } } if(!flag) { //ip被限制,跳到指定頁(yè)面 request.getRequestDispatcher("WEB-INF/success/error.jsp").forward(request, response); } } } @Override public void destroy() { System.out.println("過(guò)濾器IpFilter結(jié)束。"); } /** * 對(duì)配置文件進(jìn)行初始化并校驗(yàn) * @author 歐陽(yáng) * @serialData 20180728 * @throws IOException */ public void initConfig() throws IOException { //將文件轉(zhuǎn)化成流 InputStream inputStream = IpFilter.class.getResourceAsStream("../config/ipConfig.properties"); Properties properties = new Properties(); //通過(guò)Properties對(duì)象實(shí)例加載流 properties.load(inputStream); //獲取三種配置方式的值 String allowIP = properties.getProperty("allowIP"); String allowIPRange = properties.getProperty("allowIPRange"); String allowIPWildcard = properties.getProperty("allowIPWildcard"); //校驗(yàn),校驗(yàn)失敗后拋出異常 if(!validate(allowIP, allowIPRange, allowIPWildcard)) { throw new RuntimeException("配置文件有錯(cuò),請(qǐng)檢查!"); } /* * 將每一種配置方法放置到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) { //對(duì)每一段進(jìn)行遍歷 for(String allowRanges : allowIPRanges) { if(allowRanges != null && !"".equals(allowRanges.trim())) { //對(duì)該段的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段地址的前三段,因?yàn)槠鹗己徒Y(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("配置文件有錯(cuò),請(qǐng)檢查!"); } } } } } //將第三種配置方法放到allowList中 if(allowIPWildcard != null && !"".equals(allowIPWildcard)) { //獲取每個(gè)含通配符的ip地址 String[] allowIPWildcards = allowIPWildcard.split(",|;"); if(allowIPWildcards.length > 0) { for(String ip : allowIPWildcards) { if(ip.indexOf("*") != -1) { //對(duì)*進(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("配置文件有錯(cuò),請(qǐng)檢查!"); } } } } //打印輸出allowList for(String str : allowList) { System.out.println(str); } } /** * 對(duì)配置文件進(jìn)行校驗(yà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)"; //整個(gè)ip的正則 String ipRegx = regx + "\\." + regx + "\\."+ regx + "\\." + regx; //對(duì)第一種方式進(jìn)行校驗(yàn) Pattern pattern = Pattern.compile("("+ipRegx+")|("+ipRegx+"(,|;))*"); if(this.isNullorMatches(allowIP, pattern)){ result = true; //匹配成功 } else { result = false; } //對(duì)第二種方式進(jìn)行校驗(yàn) pattern = Pattern.compile("("+ipRegx+")\\-("+ipRegx+")|" + "(("+ipRegx+")\\-("+ipRegx+")(,|;))*"); if(this.isNullorMatches(allowIPRange, pattern)){ result = true; //匹配成功 } else { result = false; } //對(duì)第三種方式進(jìn)行校驗(yà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 歐陽(yáng) * @serialData 20180728 * @param allow * @return */ public Boolean isNullorMatches(String allow, Pattern pattern) { //如果為空,說(shuō)明用戶沒(méi)添加該項(xiàng),不做處理 if(allow == null || "".equals(allow.trim())) { return true; } else { //在最后面沒(méi)有,或;的給添上 if(!allow.endsWith(";") && !allow.endsWith(",")) { allow += ";"; } //如果匹配,則返回true if(pattern.matcher(allow).matches()) { return true; } } return false; } }
到此這篇關(guān)于詳解Java Web如何限制訪問(wèn)的IP的兩種方法的文章就介紹到這了,更多相關(guān)Java 限制訪問(wèn)的IP內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
說(shuō)一說(shuō)java關(guān)鍵字final和transient
這篇文章主要和大家說(shuō)一說(shuō)java關(guān)鍵字final和transient,感興趣的小伙伴們可以參考一下2016-06-06Java?Web項(xiàng)目中解決中文亂碼方法總結(jié)(三種最新方法)
這篇文章主要介紹了Java?Web項(xiàng)目中解決中文亂碼方法總結(jié),本文給大家分享三種最新解決方法,需要的朋友可以參考下2022-06-06Java處理時(shí)間格式CST和GMT轉(zhuǎn)換方法示例
這篇文章主要給大家介紹了關(guān)于Java處理時(shí)間格式CST和GMT轉(zhuǎn)換方法的相關(guān)資料,相信很多小伙伴在時(shí)間格式轉(zhuǎn)換的時(shí)候非常頭疼,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09