Java 在Spring Boot中区分嵌入式Tomcat中多个连接器/端口的请求

Java 在Spring Boot中区分嵌入式Tomcat中多个连接器/端口的请求,java,spring-boot,tomcat,port,Java,Spring Boot,Tomcat,Port,我在多个端口上配置了一个基于Spring Boot rest服务的应用程序,该应用程序需要区分每个请求所经过的端口。为应用程序提供多个端口的想法是由于不同的公共和私有子网(具有不同的安全访问级别)可以访问应用程序公开的服务的不同部分 从概念上讲,这个想法是向嵌入式tomcat添加额外的连接器,然后通过向每个连接器添加一个自定义头来捕获所有传入的请求,并指定它所经过的“通道” 我面临的问题是,我不知道如何在连接器级别捕获这些传入请求(在它到达任何过滤器或servlet之前) 因此,对于多端口解决方

我在多个端口上配置了一个基于Spring Boot rest服务的应用程序,该应用程序需要区分每个请求所经过的端口。为应用程序提供多个端口的想法是由于不同的公共和私有子网(具有不同的安全访问级别)可以访问应用程序公开的服务的不同部分

从概念上讲,这个想法是向嵌入式tomcat添加额外的连接器,然后通过向每个连接器添加一个自定义头来捕获所有传入的请求,并指定它所经过的“通道”

我面临的问题是,我不知道如何在连接器级别捕获这些传入请求(在它到达任何过滤器或servlet之前)

因此,对于多端口解决方案,我有:

@Configuration
public class EmbeddedTomcatConfiguration {

    @Value("${server.additional-ports}")
    private String additionalPorts;

    @Bean
    public TomcatServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        Connector[] additionalConnectors = additionalConnector();
        if(additionalConnectors != null && additionalConnectors.length > 0) {
            tomcat.addAdditionalTomcatConnectors(additionalConnectors);
        }
        return tomcat;
    }

    private Connector[] additionalConnector() {
        if(StringUtils.isNotBlank(additionalPorts)) {
            return Arrays.stream(additionalPorts.split(","))
                .map(String::trim)
                .map(p -> {
                    Connector connector = new Connector(Http11NioProtocol.class.getCanonicalName());
                    connector.setScheme("http");
                    connector.setPort(Integer.valueOf(p));
                    return connector;
                })
                .toArray(Connector[]::new);
        }
        return null;
    }
}
理论上,我可以为每个连接器注册一个定制的
LifecycleListener
,但据我所知,它不会有帮助。我也听说过一些关于阀门的事情,尽管我不知道如何在每个连接器上实现它们

也许我走错了路


我真的非常感谢您在这件事上的任何帮助。

您似乎一心想尝试一个瓣膜,但是,经过更多的研究,我建议您使用ServletFilter来完成这项工作,而不是瓣膜

我相信您可以在Valve中完成这项工作,但是Valve必须部署到tomcat/lib目录中,而不是打包在应用程序中。我将敦促您考虑将您的应用程序保持在可部署工件中,而不是必须记住在创建新部署时将一个额外的JAR文件部署到您的Tomcat实例。 从这个答案中,您应该能够通过在HttpServletRequest上调用getLocalPort()来访问tomcat端口

然后根据你在问题中的想法添加一个

理论上,完成之后,您应该能够使用@RequestMapping注释根据头中的名称进行路由

@PreAuthorize("hasPermission(#your_object, 'YOUR_OBJECT_WRITE')")
@RequestMapping("/yourobject/{identifier}", headers="context=<context_name>", method = RequestMethod.POST)
public String postYourObject(@PathVariable(value = "identifier") YourObject yourObject) {
    // Do something here...
    ...
}
@PreAuthorize(“hasPermission(#您的#u对象,'您的#u对象_WRITE'))
@RequestMapping(“/yourobject/{identifier}”,headers=“context=”,method=RequestMethod.POST)
公共字符串postYourObject(@PathVariable(value=“identifier”)YourObject YourObject){
//在这里做点什么。。。
...
}

嗯,您很可能可以添加一个自定义阀,但我认为端口号是请求头的一部分。如果是这种情况,您可以根据该端口号进行授权,而不是自己添加到请求中。此外,@RequestMapping注释可以基于头值进行路由,这意味着您还可以使用@PreAuthorize注释对每个映射方法进行单独授权。啊,我忘了提到,这些服务是通过不同域名下的网关公开的(都使用80或443)。因此,实际请求将不具有正确的端口信息。关于阀门:您知道如何将一些连接器标识符传递给自定义阀门实现吗?要直接回答您的问题,不,我不知道如何完成这项工作,但是,是的,您应该能够创建一个新的阀门并实现您希望执行的行为。要查找的阀门可能类似于。您是对的。实际上,这就是我最终实现的解决方案。谢谢
@PreAuthorize("hasPermission(#your_object, 'YOUR_OBJECT_WRITE')")
@RequestMapping("/yourobject/{identifier}", headers="context=<context_name>", method = RequestMethod.POST)
public String postYourObject(@PathVariable(value = "identifier") YourObject yourObject) {
    // Do something here...
    ...
}