Java Web项目通过filter限制IP访问及路由拦截

背景

web开发中出于安全方面的考虑,对于后台管理项目通常会对用户访问做限制,常见的做法是硬件上设置白名单,过滤掉不需要的IP访问来保证管理平台的安全。但是在硬件操作不方便的情形之下,就需要开发人员通过程序对访问的IP进行限制,具体的实现方式可能会受到实际环境的影响而稍有不同,本文针对直接部署在tomcat下web项目(且无nginx或其他形式做代理)做一下详细说明。

实现

思路梳理

首先在web.xml中配置相应的参数,然后自定义一个filter实现Filter接口:在子定义的filter里面的init方法和doFilter方法进行处理。init方法中获取web.xml中配置的允许访问的IP白名单,并对其进行有效性验证及格式处理,定义为集合allow;doFilter方法中从请求中获取请求来源的IP地址,验证地址有效性,遍历集合allow,比较获取的来源IP是否在集合allow中存在,存在就放行,不存在response用数据流的形式返回“您的IP被限制访问!”信息给访问者,至此,IP限制部分介绍完毕。文中剩余内容是对请求路由的限制实现,也可供参考。

代码实现

web.xml配置过滤器及IP白名单
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <filter>
    <filter-name>loginFilter</filter-name>
    <filter-class>com.bjdata.oldsite.LoginFilter</filter-class>
    <init-param>
      <param-name>AllowIPList</param-name>
      <param-value>
        192.168.0.* ;
        219.143.182.110 ;
        192.168.20.140-192.168.20.205
      </param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>loginFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>


自定义过滤器init()方法获取定义白名单
package com.bjdata.oldsite;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @Auther:
 * @Date:
 * @Description:
 */
public class LoginFilter implements Filter {

    // 允许的IP访问列表
    private Set<String> ipList = new HashSet<String>();

    // IP的正则
    private Pattern pattern = Pattern
            .compile("(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})");

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 从web.xml读取参数
        String allowIp = filterConfig.getInitParameter("AllowIPList");

        // 转换IP地址
        init(allowIp);
        System.err.println("Allow IP list:" + ipList);
    }

    /**
     * 转换IP地址的形式
     * @param allowIp
     */
    private void init(String allowIp) {

        // 192.168.0.*转换为192.168.0.1-192.168.0.255
        for (String allow : allowIp.replaceAll("\\s", "").split(";")) {
            if (allow.indexOf("*") > -1) {
                String[] ips = allow.split("\\.");
                String[] from = new String[]{"0", "0", "0", "0"};
                String[] end = new String[]{"255", "255", "255", "255"};

                List<String> tem = new ArrayList<>();
                for (int i = 0; i < ips.length; i++) {
                    if (ips[i].indexOf("*") > -1) {
                        tem = complete(ips[i]);
                        from[i] = null;
                        end[i] = null;
                    }else {
                        from[i] = ips[i];
                        end[i] = ips[i];
                    }
                }

                StringBuilder fromIP = new StringBuilder();
                StringBuilder endIP = new StringBuilder();
                for (int i = 0; i < 4; i++) {
                    if (from[i] != null) {
                        fromIP.append(from[i]).append(".");
                        endIP.append(end[i]).append(".");
                    }else {
                        fromIP.append("[*].");
                        endIP.append("[*].");
                    }
                }
                fromIP.deleteCharAt(fromIP.length() - 1);
                endIP.deleteCharAt(endIP.length() - 1);

                for (String s : tem) {
                    String ip = fromIP.toString().replace("[*]",
                            s.split(";")[0])
                            + "-"
                            + endIP.toString().replace("[*]", s.split(";")[1]);
                    if (validate(ip)) {
                        ipList.add(ip);
                    }
                }
            }else {
                if (validate(allow)) {
                    ipList.add(allow);
                }
            }
        }

    }

    /**
     * 在添加至白名单时进行格式校验
     * @param allow
     * @return
     */
    private boolean validate(String allow) {
        for (String s : allow.split("-")){
            if (!pattern.matcher(s).matches()) {
                return false;
            }
        }
        return true;
    }


    /**
     * 对单个IP节点进行范围限定
     * @param ip
     * @return 返回限定后的IP范围,格式为List[10;19, 100;199]
     */
    private List<String> complete(String ip) {
        List<String> com = new ArrayList<>();
        if (ip.length() == 1) {
            com.add("0;255");
        }else if (ip.length() == 2) {
            String s1 = complete(ip, 1);
            if (s1 != null){
                com.add(s1);
            }
            String s2 = complete(ip, 2);
            if (s2 != null) {
                com.add(s2);
            }
        }else {
            String s1 = complete(ip, 1);
            if (s1 != null) {
                com.add(s1);
            }
        }
        return com;
    }

    /**
     * 字符串格式处理
     * @param ip
     * @param length
     * @return
     */
    private String complete(String ip, int length) {
        String from = "";
        String end = "";
        if (length == 1) {
            from = ip.replace("*", "0");
            end = ip.replace("*", "9");
        }else{
            from = ip.replace("*", "00");
            end = ip.replace("*", "99");
        }
        if (Integer.valueOf(from) > 255){
            return null;
        }

        if (Integer.valueOf(end) > 255) {
            end = "255";
        }

        return from + ";" + end;
    }

}


自定义过滤器doFilter()方法获取请求IP并验证是否属于白名单

package com.bjdata.oldsite;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @Auther:
 * @Date:
 * @Description:
 */
public class LoginFilter implements Filter {




    // 允许的IP访问列表
    private Set<String> ipList = new HashSet<String>();

    // IP的正则
    private Pattern pattern = Pattern
            .compile("(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})");



    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        // 登录IP控制
        String ip = request.getRemoteAddr();
        InetAddress inet = null;
        try {
            inet = InetAddress.getLocalHost();
            if (ip.equals("127.0.0.1")){
                ip = inet.getHostAddress();
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        if (!checkLoginIP(ip)) {
            response.getOutputStream().write(("您的IP被限制访问!").getBytes());
            /*response.getOutputStream().write((ip + "ip forbidden.").getBytes());*/
            response.getOutputStream().flush();
            return;
        }

        // 登录路由控制
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        if(request.getRequestURI().indexOf("login.jsp")<0 && !requestURI.equals("/oldSite/getValidateCode.jsp")){
            HttpSession session = request.getSession();
            String sessionKey = (String)session.getAttribute("sessionKey");
            if(sessionKey==null){
                response.sendRedirect("login.jsp");
            }
        }

        // 放行
        filterChain.doFilter(request,response);
    }


    /**
     * 检查IP是否是允许的IP
     * @param ip
     * @return
     */
    private boolean checkLoginIP(String ip) {
        if (ipList.isEmpty() || ipList.contains(ip)) {
            return true;
        }else{
            for (String allow : ipList) {
                if (allow.indexOf("-") > -1){
                   String[] from = allow.split("-")[0].split("\\.");
                   String[] end = allow.split("-")[1].split("\\.");
                   String[] tag = ip.split("\\.");

                   // 对IP从左到右进行逐段匹配
                    boolean check = true;
                    for (int i = 0; i < 4; i++) {
                        int s = Integer.valueOf(from[i]);
                        int t = Integer.valueOf(tag[i]);
                        int e = Integer.valueOf(end[i]);
                        if (!(s <= t && t <= e)) {
                            check = false;
                            break;
                        }
                    }
                    if (check) {
                        return true;
                    }
                }
            }
        }

        return false;
    }
}

自定义Filter中所有代码摘录如下
package com.bjdata.oldsite;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @Auther:
 * @Date:
 * @Description:
 */
public class LoginFilter implements Filter {




    // 允许的IP访问列表
    private Set<String> ipList = new HashSet<String>();

    // IP的正则
    private Pattern pattern = Pattern
            .compile("(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
            + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})");

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 从web.xml读取参数
        String allowIp = filterConfig.getInitParameter("AllowIPList");

        // 转换IP地址
        init(allowIp);
        System.err.println("Allow IP list:" + ipList);
    }


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        // 登录IP控制
        String ip = request.getRemoteAddr();
        InetAddress inet = null;
        try {
            inet = InetAddress.getLocalHost();
            if (ip.equals("127.0.0.1")){
                ip = inet.getHostAddress();
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        if (!checkLoginIP(ip)) {
            response.getOutputStream().write(("您的IP被限制访问!").getBytes());
            /*response.getOutputStream().write((ip + "ip forbidden.").getBytes());*/
            response.getOutputStream().flush();
            return;
        }

        // 登录路由控制
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        if(request.getRequestURI().indexOf("login.jsp")<0 && !requestURI.equals("/oldSite/getValidateCode.jsp")){
            HttpSession session = request.getSession();
            String sessionKey = (String)session.getAttribute("sessionKey");
            if(sessionKey==null){
                response.sendRedirect("login.jsp");
            }
        }

        // 放行
        filterChain.doFilter(request,response);
    }



    @Override
    public void destroy() {

    }

    /**
     * 转换IP地址的形式
     * @param allowIp
     */
    private void init(String allowIp) {

        // 192.168.0.*转换为192.168.0.1-192.168.0.255
        for (String allow : allowIp.replaceAll("\\s", "").split(";")) {
            if (allow.indexOf("*") > -1) {
                String[] ips = allow.split("\\.");
                String[] from = new String[]{"0", "0", "0", "0"};
                String[] end = new String[]{"255", "255", "255", "255"};

                List<String> tem = new ArrayList<>();
                for (int i = 0; i < ips.length; i++) {
                    if (ips[i].indexOf("*") > -1) {
                        tem = complete(ips[i]);
                        from[i] = null;
                        end[i] = null;
                    }else {
                        from[i] = ips[i];
                        end[i] = ips[i];
                    }
                }

                StringBuilder fromIP = new StringBuilder();
                StringBuilder endIP = new StringBuilder();
                for (int i = 0; i < 4; i++) {
                    if (from[i] != null) {
                        fromIP.append(from[i]).append(".");
                        endIP.append(end[i]).append(".");
                    }else {
                        fromIP.append("[*].");
                        endIP.append("[*].");
                    }
                }
                fromIP.deleteCharAt(fromIP.length() - 1);
                endIP.deleteCharAt(endIP.length() - 1);

                for (String s : tem) {
                    String ip = fromIP.toString().replace("[*]",
                            s.split(";")[0])
                            + "-"
                            + endIP.toString().replace("[*]", s.split(";")[1]);
                    if (validate(ip)) {
                        ipList.add(ip);
                    }
                }
            }else {
                if (validate(allow)) {
                    ipList.add(allow);
                }
            }
        }

    }

    /**
     * 在添加至白名单时进行格式校验
     * @param allow
     * @return
     */
    private boolean validate(String allow) {
        for (String s : allow.split("-")){
            if (!pattern.matcher(s).matches()) {
                return false;
            }
        }
        return true;
    }


    /**
     * 对单个IP节点进行范围限定
     * @param ip
     * @return 返回限定后的IP范围,格式为List[10;19, 100;199]
     */
    private List<String> complete(String ip) {
        List<String> com = new ArrayList<>();
        if (ip.length() == 1) {
            com.add("0;255");
        }else if (ip.length() == 2) {
            String s1 = complete(ip, 1);
            if (s1 != null){
                com.add(s1);
            }
            String s2 = complete(ip, 2);
            if (s2 != null) {
                com.add(s2);
            }
        }else {
            String s1 = complete(ip, 1);
            if (s1 != null) {
                com.add(s1);
            }
        }
        return com;
    }

    /**
     * 字符串格式处理
     * @param ip
     * @param length
     * @return
     */
    private String complete(String ip, int length) {
        String from = "";
        String end = "";
        if (length == 1) {
            from = ip.replace("*", "0");
            end = ip.replace("*", "9");
        }else{
            from = ip.replace("*", "00");
            end = ip.replace("*", "99");
        }
        if (Integer.valueOf(from) > 255){
            return null;
        }

        if (Integer.valueOf(end) > 255) {
            end = "255";
        }

        return from + ";" + end;
    }


    /**
     * 检查IP是否是允许的IP
     * @param ip
     * @return
     */
    private boolean checkLoginIP(String ip) {
        if (ipList.isEmpty() || ipList.contains(ip)) {
            return true;
        }else{
            for (String allow : ipList) {
                if (allow.indexOf("-") > -1){
                   String[] from = allow.split("-")[0].split("\\.");
                   String[] end = allow.split("-")[1].split("\\.");
                   String[] tag = ip.split("\\.");

                   // 对IP从左到右进行逐段匹配
                    boolean check = true;
                    for (int i = 0; i < 4; i++) {
                        int s = Integer.valueOf(from[i]);
                        int t = Integer.valueOf(tag[i]);
                        int e = Integer.valueOf(end[i]);
                        if (!(s <= t && t <= e)) {
                            check = false;
                            break;
                        }
                    }
                    if (check) {
                        return true;
                    }
                }
            }
        }

        return false;
    }
}


转载于:https://my.oschina.net/u/3193075/blog/3063761

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中,可以通过使用 Servlet Filter 来实现限制指定 IP 访问接口的功能。以下是示例代码: 1. 创建一个 IPFilter 类: ```java import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class IPFilter implements Filter { private String allowedIP; @Override public void init(FilterConfig filterConfig) throws ServletException { allowedIP = filterConfig.getInitParameter("allowedIP"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; String clientIP = req.getRemoteAddr(); if (clientIP.equals(allowedIP)) { chain.doFilter(request, response); } else { res.setStatus(HttpServletResponse.SC_FORBIDDEN); } } @Override public void destroy() { } } ``` 2. 在 web.xml 文件中配置 Filter: ```xml <filter> <filter-name>IPFilter</filter-name> <filter-class>IPFilter</filter-class> <init-param> <param-name>allowedIP</param-name> <param-value>127.0.0.1</param-value> </init-param> </filter> <filter-mapping> <filter-name>IPFilter</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping> ``` 在上述代码中,将 `allowedIP` 参数设置为允许访问接口的 IP 地址。并且将 Filter 映射到 `/api/*` URL 上,以便过滤需要限制的接口。当客户端访问接口时,Filter 会检查客户端 IP 地址是否与 `allowedIP` 相同,并根据结果返回 HTTP 状态码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值