You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使Google App Engine中的Servlet仅可在本地主机访问?附代码

Restrict JAX-RS Servlet on Google App Engine to Localhost Only

Got it, let's break down how to make your com.practice.Hello JAX-RS endpoint (at /keyboard) only accessible from localhost—whether you're running the local dev server or deployed on Google App Engine (GAE).

Option 1: Add Access Control Directly in the JAX-RS Resource

This is straightforward if you only need to restrict a single endpoint. Just embed the localhost check right in your resource method:

package com.practice;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;

@Path("/keyboard")
public class Hello {

    @GET
    public Response getKeyboard(@Context HttpHeaders headers) {
        // Get client IP (handle GAE's reverse proxy with X-Forwarded-For)
        String clientIp = headers.getRequestHeader("X-Forwarded-For") != null 
            ? headers.getRequestHeader("X-Forwarded-For").get(0).split(",")[0].trim()
            : headers.getRequestHeader("Remote-Addr").get(0);

        // Block non-localhost requests
        if (!"127.0.0.1".equals(clientIp) && !"localhost".equals(clientIp)) {
            return Response.status(Response.Status.FORBIDDEN)
                .entity("{\"error\": \"Access denied: Only localhost access is allowed\"}")
                .build();
        }

        // Return your normal JSON response
        return Response.ok("{\"message\": \"Success - localhost access granted\"}")
            .build();
    }
}

Option 2: Use a Servlet Filter (Better for Multiple Endpoints)

If you have multiple endpoints to restrict, a filter lets you apply the check globally to specific paths—no need to duplicate code across resources.

Step 1: Create the Filter Class

package com.practice;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LocalhostOnlyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Optional initialization logic (if needed)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // Resolve client IP (account for GAE's proxy)
        String clientIp = httpRequest.getHeader("X-Forwarded-For");
        if (clientIp == null) {
            clientIp = httpRequest.getRemoteAddr();
        } else {
            // X-Forwarded-For may have multiple IPs; take the first one
            clientIp = clientIp.split(",")[0].trim();
        }

        // Allow localhost + optional internal GAE service calls
        boolean isLocal = "127.0.0.1".equals(clientIp) || "localhost".equals(clientIp);
        boolean isInternalGaeCall = httpRequest.getHeader("X-Appengine-Inbound-Appid") != null
                && httpRequest.getHeader("X-Appengine-Inbound-Appid")
                        .equals(System.getProperty("com.google.appengine.application.id"));

        if (isLocal || isInternalGaeCall) {
            chain.doFilter(request, response);
        } else {
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            httpResponse.setContentType("application/json");
            httpResponse.getWriter().write("{\"error\": \"Access denied: Only localhost or internal GAE services allowed\"}");
        }
    }

    @Override
    public void destroy() {
        // Optional cleanup logic (if needed)
    }
}

Step 2: Configure the Filter in web.xml

Add this snippet to your web.xml to map the filter to your /keyboard endpoint:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- JAX-RS Servlet Setup -->
    <servlet>
        <servlet-name>Jersey Servlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.practice</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <!-- Localhost Filter Mapping -->
    <filter>
        <filter-name>LocalhostOnlyFilter</filter-name>
        <filter-class>com.practice.LocalhostOnlyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LocalhostOnlyFilter</filter-name>
        <url-pattern>/keyboard</url-pattern>
    </filter-mapping>
</web-app>

Key Notes for GAE Deployment

  • Reverse Proxy Handling: GAE routes requests through a proxy, so getRemoteAddr() returns the proxy's IP instead of the client's. Always use the X-Forwarded-For header to get the real client IP.
  • Internal GAE Calls: If you need to allow access from other services in the same GAE project, use the X-Appengine-Inbound-Appid header to verify the request comes from your app (the check is included in the filter example above).

内容的提问来源于stack exchange,提问作者user8931048

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:47:13