【问题标题】:Get corresponding https port number for http port in Tomcat获取Tomcat中http端口对应的https端口号
【发布时间】:2012-09-06 22:03:50
【问题描述】:

我正在尝试最小化我的 webapp 的配置,我想要删除的一件事是端口号映射:

  • http: 80 -> https: 443
  • http: 9080 -> https: 9443

由于配置已经存在于 conf/server.xml 中,我不想在我的应用程序中复制这些设置。不得不更改(并记住更改)多个配置文件是一件痛苦的事。此外,应用程序不应该关心它被部署到什么环境/容器中,只要它支持 http 和 https。

我在 web.xml 中配置了以下内容,但除了重定向之外,我还需要能够构建 https URL:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>secure</web-resource-name>
        <url-pattern>/https/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

上面的代码块告诉 servlet 容器将 http 请求重定向到它的 https 对应物。显然,Tomcat 知道请求来自哪个连接器,在 server.xml 中查找该连接器的“redirectPort”属性并使用该连接器构建 https URL。

根据这些先前/相关的问题,似乎没有标准或特定于 tomcat 的方式来获取请求的相应 https 端口:

TL;DR:我的问题是,你有什么想法可以为不安全的请求获取相应的 https 端口号,而无需在 webapp 中明确配置它们?

我的一个想法是使用与当前请求相同的端口号,从 webapp 向自身发起一个 http 调用到安全约束后面的路径,并从响应中解析重定向位置。当然,响应应该被缓存。有没有更直接的方法?

编辑:添加了 answer 以及该想法的代码。

【问题讨论】:

    标签: java jakarta-ee tomcat servlets


    【解决方案1】:

    如果有人想知道如何实现我在问题中提出的想法,这里有一些示例代码我放在一起来测试它。不过,我不认为我会采用这种解决方案。

    这适用于问题正文中的安全约束块。

    private static final String HTTPS_CONSTRAINED_PATH = "/https";
    
    private static ConcurrentHashMap<String, Integer> resolvedHttpsPortMap = new ConcurrentHashMap<String, Integer>();
    private static final ReentrantLock portMapLock = new ReentrantLock();
    
    public static int resolveHttpsPort(HttpServletRequest request) {
        if (request.isSecure()) return request.getServerPort();
        String key = request.getServerName() + ":" + request.getServerPort();
        Integer port = resolvedHttpsPortMap.get(key);
        if (port == null) {
            portMapLock.lock();
            try {
                port = resolvedHttpsPortMap.get(key);
                if (port == null) {
                    URL url = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), request.getContextPath() + HTTPS_CONSTRAINED_PATH);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    if (conn.getResponseCode() != 301 && conn.getResponseCode() != 302
                            && conn.getResponseCode() != 303 && conn.getResponseCode() != 307) {
                        throw new IllegalStateException("Got unexpected response code " + conn.getResponseCode() + " from URL: " + url);
                    }
                    String location = conn.getHeaderField("Location");
                    if (location == null) {
                        throw new IllegalStateException("Did not get a Location header in the response from URL: " + url);
                    }
                    URL locationUrl = new URL(location);
                    port = locationUrl.getPort();
                }
            } catch (Exception e) {
                logger.warn("Could not determine corresponding HTTPS port for '" + key + "'", e);
            } finally {
                if (port == null) port = -1;
                resolvedHttpsPortMap.put(key, port);
                portMapLock.unlock();
            }
        }
        return port;
    }
    

    【讨论】:

      【解决方案2】:

      我完全不明白您为什么需要知道安全端口号。如果正在访问的资源被标记为需要 SSL,Tomcat 将发送重定向到 https: 和适当的安全端口。这就是 server.xml 中的配置。

      【讨论】:

      • 您好 EJP,请考虑不安全的主页包含注册表单的情况(例如 facebook.comtwitter.com)。如何在不知道 https 端口(如果不是 443)的情况下为表单操作生成 https URL? Tomcat 重定向是不够的,因为用户在重定向到安全 URL 之前会不安全地发布他/她的数据。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 2020-09-15
      • 1970-01-01
      • 2019-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多