Java Web如何限制访问的IP的两种方法

Java Web限制IP访问的两种方法

  前一阵子因为在做项目时碰到了这个功能,现在好好总结一下,至于为什么要限制IP访问,我就不多说了。然后百度了一下,现在主要有两种方式去限制IP访问,第一种是最简单的方便的,第二种是通过过滤器来限制访问。下面我简单介绍一下第一种方式,着重介绍第二种。

第一种方式(Tomcat配置项配置允许或限制IP访问)

  这种是最简单的快捷的,主要就涉及Tomcat的server.xml配置。
第一步:找到server.xml文件在哪,在Tomcat的目录下的conf文件夹下。
第二步:打开server.xml文件,找到Host节点,在其中加上:

<Valve className="org.apache.catalina.valves.RemoteAddrValve" 
    allow="127.0.0.1" 
    deny=""/>

其中:
className:表示java类名,必须是
org.apache.catalina.valves.RemoteHostValveorg.apache.catalina.valves.RemoteAddrValve
allow:表示允许的IP,支持模糊(*),多个用,隔开;
deny:表示限制的IP,支持模糊(*);多个用,隔开。
注:如果是限制某一个站点(网站)则在Context节点中添加。
第三步:重启Tomcat。

第二种方式(通过Filter过滤器来配置允许或限制IP访问)

(1)代码实现的思路

  通过增加配置文件properties,将允许访问的IP按一定规则配置进去;接下来再对配置文件(这里尚且叫做配置文件)进行加载;然后再对配置文件的格式要求通过正则进行校验;其次将配置的IP通过一个集合进行收集,可收集单条IP或一个IP的正则,因为我们这里需要用到模糊;最后对访问者的IP与集合中的进行比对,比对通过则正常访问,否则。反之。
  在配置文件中提供三种最常见的IP配置方式:
1. 单个IP地址的配置,多个之间用逗号或分好隔开;
例如:192.168.1.50;127.0.0.1;
2. IP地址区间方式的配置,多个区间用逗号或分好隔开;
例如:172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89
3. 通配符,多个用逗号或分好隔开。
例如:172.20.30.*

(2)具体实现代码

第一步:编写配置文件/Test/src/com/config/ipConfig.properties;

#单个IP地址的配置,多个之间用逗号或分好隔开
allowIP=192.168.1.50;127.0.0.1;

#IP地址区间方式的配置,多个区间用逗号或分好隔开
allowIPRange=172.20.32.10-172.20.32.11;172.20.32.88-172.20.32.89

#通配符,多个用逗号或分好隔开
allowIPWildcard=172.20.30.*;

第二步:新建Java类实现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>

 <!-- 结束过滤器 -->

第四步:我们需要声明一个全局变量List来存放允许访问的IP或正则式;

//声明的代码:
//用来存放允许访问的ip
private List<String> allowList = new ArrayList<String>();

第五步:需要对配置文件进行加载;在方法init中

//加载的代码:
//将文件转化成流
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())) {
    //先进行每一段的分割
    String[] allowIPRanges = allowIPRange.split(",|;");

    if(allowIPRanges.length > 0) {
        //对每一段进行遍历
        for(String allowRanges : allowIPRanges) {
            if(allowRanges != null && 
                    !"".equals(allowRanges.trim())) {
                //对该段的ip进行解析
                String[] ips = allowRanges.split("-");
                if(ips.length > 0 && ips.length < 3) {
                    String from = ips[0];//得到该段的起始ip
                    String to = ips[1];  //得到该段的结束ip

                    //获取该ip段地址的前三段,因为起始和结束的ip的前三段一样
                    String share = from.substring(0, from.lastIndexOf(".")+1);

                    //获取该ip段的起始ip的最后一段
                    int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1, 
                                                        from.length()));
                    //获取该ip段的结束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) {
                //对*进行替换
                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比对,成功匹配就正常访问,反之则跳到错误页面。这个因为是在用户访问时才进行的步骤,需要在doFilter方法的编写。

//获取访问的IP地址
String remoteAddr = request.getRemoteAddr();
//System.out.println("===============" + remoteAddr);
//如果allowList为空,则认为没做限制,不为空则检查是否限制
if(allowList.size() == 0 || allowList == null) {
    filterChain.doFilter(request, response);
} else {
    Boolean flag = false;  //访问标志,默认为false,限制访问
    //进行逐个检查
    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进行限制访问
 * @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为空,则认为没做限制,不为空则检查是否限制
        if(allowList.size() == 0 || allowList == null) {
            filterChain.doFilter(request, response);
        } else {
            Boolean flag = false;  //访问标志,默认为false,限制访问
            //进行逐个检查
            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结束。");
    }

    /**
     * 对配置文件进行初始化并校验
     * @author 欧阳
     * @serialData 20180728
     * @throws IOException
     */
    public void initConfig() throws IOException {
        //将文件转化成流
        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())) {
            //先进行每一段的分割
            String[] allowIPRanges = allowIPRange.split(",|;");

            if(allowIPRanges.length > 0) {
                //对每一段进行遍历
                for(String allowRanges : allowIPRanges) {
                    if(allowRanges != null && 
                            !"".equals(allowRanges.trim())) {
                        //对该段的ip进行解析
                        String[] ips = allowRanges.split("-");
                        if(ips.length > 0 && ips.length < 3) {
                            String from = ips[0];//得到该段的起始ip
                            String to = ips[1];  //得到该段的结束ip

                            //获取该ip段地址的前三段,因为起始和结束的ip的前三段一样
                            String share = from.substring(0, from.lastIndexOf(".")+1);

                            //获取该ip段的起始ip的最后一段
                            int start = Integer.parseInt(from.substring(from.lastIndexOf(".")+1, 
                                                                from.length()));
                            //获取该ip段的结束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) {
                        //对*进行替换
                        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);
        }

    }

    /**
     * 对配置文件进行校验
     * @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;

        //对第一种方式进行校验
        Pattern pattern = Pattern.compile("("+ipRegx+")|("+ipRegx+"(,|;))*");
        if(this.isNullorMatches(allowIP, pattern)){
            result = true;  //匹配成功
        } else {
            result = false;
        }

        //对第二种方式进行校验
        pattern = Pattern.compile("("+ipRegx+")\\-("+ipRegx+")|" + 
                        "(("+ipRegx+")\\-("+ipRegx+")(,|;))*");
        if(this.isNullorMatches(allowIPRange, pattern)){
            result = true;  //匹配成功
        } else {
            result = false;
        }

        //对第三种方式进行校验
        pattern = Pattern.compile("("+regx+"\\."+ regx+"\\."+regx+"\\."+ "\\*)|" + 
                        "("+regx+"\\."+regx+"\\."+regx+"\\."+ "\\*(,|;))*");
        if(this.isNullorMatches(allowIPWildcard, pattern)){
            result = true;  //匹配成功
        } else {
            result = false;
        }

        return result;
    }

    /**
     * 进行正则匹配
     * @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;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_24598601/article/details/81268723