如何使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 theX-Forwarded-Forheader 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-Appidheader to verify the request comes from your app (the check is included in the filter example above).
内容的提问来源于stack exchange,提问作者user8931048
相关产品推荐
相关产品推荐

