配置tomcat限制指定IP地址访问后端应用

1. 场景
后端存在N个tomcat实例,前端通过nginx反向代理和负载均衡。

    tomcat1      tomcatN
        |                 |
        |                 |
      -----------------
                |    
             nginx

2. 需求
为了保护后端应用,tomcat实例只允许前端nginx服务器IP访问,其他任何地址的访问都被拒绝。


3. 实现
编辑${TOMCAT_HOME}/conf/server.xml,添加org.apache.catalina.valves.RemoteAddrValve配置,如下所示:

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

    <!-- SingleSignOn valve, share authentication between web applications
         Documentation at: /docs/config/valve.html -->
    <!--
    <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
    -->

    <!-- Access log processes all example.
         Documentation at: /docs/config/valve.html
         Note: The pattern used is equivalent to using pattern="common" -->
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log." suffix=".txt"
           pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    
    <!-- 限制指定IP地址访问Tomcat -->
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           allow="127.0.0.1"
           deny=""/>
</Host>


4. 原理

(1)概述
在tomcat中存在一个与容器关联的组件Valve,该组件用于处理request请求。源码注释为:


详见tomcat请求处理时序图:http://tomcat.apache.org/tomcat-8.5-doc/architecture/requestProcess/request-process.png
因此,我们可以通过添加指定Valve实现,用于在处理request请求时实现相应功能。
例如:在这里通过在<Host>元素中添加org.apache.catalina.valves.RemoteAddrValve实现限制指定IP地址访问应用程序。

(2)Valve类图

(3)源码解读

org.apache.catalina.valves.RemoteAddrValve实现Valve处理request请求接口:

 @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {
        String property;
        if (addConnectorPort) {
            property = request.getRequest().getRemoteAddr() + ";" + request.getConnector().getPort();
        } else {
            property = request.getRequest().getRemoteAddr();
        }
        process(property, request, response);
    }


org.apache.catalina.valves.RequestFilterValve process实现:

protected void process(String property, Request request, Response response)
            throws IOException, ServletException {

        if (isAllowed(property)) {
            getNext().invoke(request, response);
            return;
        }

        if (getLog().isDebugEnabled()) {
            getLog().debug(sm.getString("requestFilterValve.deny",
                    request.getRequestURI(), property));
        }

        // Deny this request
        denyRequest(request, response);
    }
public boolean isAllowed(String property) {
        // Use local copies for thread safety
        Pattern deny = this.deny;
        Pattern allow = this.allow;

        // Check the deny patterns, if any
        if (deny != null && deny.matcher(property).matches()) {
            return false;
        }

        // Check the allow patterns, if any
        if (allow != null && allow.matcher(property).matches()) {
            return true;
        }

        // Allow if denies specified but not allows
        if (deny != null && allow == null) {
            return true;
        }

        // Deny this request
        return false;
    }
原文地址:https://www.cnblogs.com/nuccch/p/6743012.html