文章

IP范围过滤实现

项目里要求实现在项目上线前社内测试团地可以正常访问系统,而外部访问用户看到的是系统尚未开放的页面。

OneCoder的第一反映就是实现一个filter,配置可访问的IP规则,通过正则进行匹配。通过的正常进入系统,不通过的redirect到指定欢迎页面。

整个代码没什么难度,核心就是一个IP规则的检验功能。考虑到配置的简便性,即一般熟悉192.168.1.*和192.168.2.1-23,这种全部匹配和范围匹配的配置方式。OneCoder决定采用拆分解析匹配的方式。规则之间用分号;分隔,是或的关系。代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.coderli.web.filter.ip;

/**
 * IP规则正则处理工具类
 *
 * @author OneCoder
 * @date 2014年10月23日 下午1:23:09
 */
public class IPRegexUtil {

     /**
      * 校验所给IP是否满足给定规则
      *
      * @author li_hongzhe @nhn.com
      * @date 2014年10月23日 下午1:38:37
      * @param ipStr
      *            待校验IP
      * @param ipPattern
      *            IP匹配规则。支持 * 匹配所有和 - 匹配范围。用分号分隔 <br>
      *            例如:10.34.163.*;10.34.162.1 -128
      * @return
      */
     public static boolean validateIP(String ipStr, String ipPattern) {
           if ( ipStr == null || ipPattern == null) {
               return false;
          }
          String[] patternList = ipPattern.split( ";");
           for (String pattern : patternList) {
               if ( passValidate(ipStr, pattern)) {
                    return true;
              }
          }
           return false;
     }

     private static boolean passValidate(String ipStr, String pattern) {
          String[] ipStrArr = ipStr.split( "\\.");
          String[] patternArr = pattern.split( "\\.");
           if ( ipStrArr. length != 4 || patternArr. length != 4) {
               return false;
          }
           int end = ipStrArr. length;
           if ( patternArr[3].contains( "-")) {
               end = 3;
              String[] rangeArr = patternArr[3].split( "-");
               int from = Integer.valueOf(rangeArr[0]).intValue();
               int to = Integer.valueOf(rangeArr[1]).intValue();
               int value = Integer.valueOf(ipStrArr[3]).intValue();
               if ( value < from || value > to) {
                    return false;
              }
          }
           for ( int i = 0; i < end; i++) {
               if ( patternArr[ i].equals( "*")) {
                    continue;
              }
               if (!patternArr[ i].equalsIgnoreCase( ipStrArr[ i])) {
                    return false;
              }
          }
           return true;
     }

}

实现过滤器如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.coderli.web.filter.ip;

import java.io.IOException;

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;

/**
* IP地址过滤器,如果IP地址在过滤的范围内,则允许访问。<br>
* 如果没在范围内,则跳转到禁止页面。
*
* @author OneCoder
* @date 2014年10月24日 上午9:54:33
*/
public class IPFilter implements Filter {

     private String ipPattern;

     @Override
     public void destroy() {
          // TODO Auto-generated method stub

     }

     @Override
     public void doFilter(ServletRequest request, ServletResponse response,
               FilterChain filterChain) throws IOException, ServletException {
          String ip = request.getRemoteHost();
          String reqUrl = ((HttpServletRequest) request).getRequestURI();
          if (reqUrl.contains("forbidden")) {
               filterChain.doFilter(request, response);
               return;
          }
          if (IPRegexUtil.validateIP(ip, ipPattern)) {
               filterChain.doFilter(request, response);
          } else {
               ((HttpServletResponse) response).sendRedirect("/shurnim/forbidden");
          }
     }

     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
          this.ipPattern = filterConfig.getInitParameter("ip-pattern");
     }

     public String getIpPattern() {
          return ipPattern;
     }

     public void setIpPattern(String ipPattern) {
          this.ipPattern = ipPattern;
     }

}

web.xml配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
     <filter>
           <filter-name >IPFilter </filter-name >
           <filter-class >com.coderli.web.filter.ip.IPFilter </filter-class >
           <init-param >
               <param-name >ip-pattern</ param-name>
                <param-value >10.34.163.169;10.34.163.1-254 </param-value >
           </init-param >
     </filter >
     <filter-mapping >
           <filter-name >IPFilter </filter-name >
           <url-pattern >/* </url-pattern >
     </filter-mapping >

代码似乎没什么好解释的,目前看似乎是满足了需求了。

本文由作者按照 CC BY 4.0 进行授权