访问通过Zuul和Apache代理的资源服务器中的远程IP地址

Tim*_*Tim 6 apache spring-security spring-cloud netflix-zuul

为了安全检查,我需要在我的资源服务中访问用户的远程IP地址.这个资源服务是一个简单的最新Spring Boot应用程序,它使用我的Eureka服务器注册自己:

@SpringBootApplication
@EnableEurekaClient
public class ServletInitializer extends SpringBootServletInitializer {
    public static void main(final String[] args) {
        SpringApplication.run(ServletInitializer.class, args);
    }
}
Run Code Online (Sandbox Code Playgroud)

我尤里卡服务器注册的所有服务都通过基于Angel.SR3我Zuul路由代理服务器的动态路由starter-zuulstarter-eureka:

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class RoutingProxyServer {
    public static void main(final String[] args) {
        SpringApplication.run(RoutingProxyServer.class, args);
    }
}
Run Code Online (Sandbox Code Playgroud)

Zuul路由代理服务器还为下一步配置AJP连接器:

@Configuration
@ConditionalOnProperty("ajp.port")
public class TomcatAjpConfig extends TomcatWebSocketContainerCustomizer {
    @Value("${ajp.port}")
    private int port;

    @Override
    public void doCustomize(final TomcatEmbeddedServletContainerFactory tomcat) {
        super.doCustomize(tomcat);

        // Listen for AJP requests
        Connector ajp = new Connector("AJP/1.3");
        ajp.setPort(port);
        tomcat.addAdditionalTomcatConnectors(ajp);
    }
}
Run Code Online (Sandbox Code Playgroud)

对动态路由zuul代理的所有请求都通过Apache代理,以便在标准443端口上提供HTTPS:

# Preserve Host when proxying so jar apps return working URLs in JSON responses
RequestHeader           set X-Forwarded-Proto "https"
ProxyPreserveHost   On
# Redirect remaining traffic to routing proxy server
ProxyPass       /       ajp://192.168.x.x:8009/
# Also update Location, Content-Location and URI headers on HTTP redirect responses
ProxyPassReverse    /       ajp://192.168.x.x:8009/
Run Code Online (Sandbox Code Playgroud)

有了这一切,资源服务就可用,但不幸的是,我从Spring Security获得的remoteAddress是Zuul代理/ Apache服务器的地址,而不是远程客户端IP地址.

在过去,我使用了一个org.springframework.security.authentication.AuthenticationDetailsSource优先于X-Forwarded-For正常的标头值remoteAddress来获取正确的IP地址,但是当我通过两个代理时,我无法知道如何将正确的远程IP地址传递给我的资源服务(Apache + Zuul) .

任何人都可以帮助我访问这两个代理背后的正确远程IP地址,或者建议一种替代方法来实现这一点吗?

Tim*_*Tim 5

原来,X-Forwarded-For标头是从原始请求中提取的,并送入Zuul进行填充HttpServletRequest#getRemoteAddr()。然后,这必须通过传递给代理后端服务RequestContext#getZuulRequestHeaders().put("X-Forwarded-For", remoteAddr)ZuulFilter即使尚未将其自身的值附加到X-Forwarded-For过滤器中,也可以通过以下操作来实现。

@Component
@Slf4j
public class XForwardedForFilter extends ZuulFilter {
private static final String X_FORWARDED_FOR = "X-Forwarded-For";

@Override
public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();

    // Rely on HttpServletRequest to retrieve the correct remote address from upstream X-Forwarded-For header
    HttpServletRequest request = ctx.getRequest();
    String remoteAddr = request.getRemoteAddr();

    // Pass remote address downstream by setting X-Forwarded for header again on Zuul request
    log.debug("Settings X-Forwarded-For to: {}", remoteAddr);
    ctx.getZuulRequestHeaders().put(X_FORWARDED_FOR, remoteAddr);

    return null;
}

@Override
public boolean shouldFilter() {
    return true;
}

@Override
public String filterType() {
    return "pre";
}

@Override
public int filterOrder() {
    return 10000;
}
}
Run Code Online (Sandbox Code Playgroud)

可能需要在代理到Zuul之前清除Apache中的标头值,以防止仅接受用户提供的任何值: RequestHeader unset X-Forwarded-For