在Tomcat中,获取与HTTP端口对应的HTTPS端口号

3
我正在尝试最小化我的Web应用程序配置,其中一件我要删除的事情是端口号映射:
  • 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端口:
- Tomcat:如何在Java中获取安全端口号? - 获取JSP页面的服务器名称和端口号以进行HTTPS
简而言之,我的问题是,您有什么想法可以在不明确配置Web应用程序中的相应HTTPS端口号的情况下获取不安全请求的相应HTTPS端口号?
我提出的一个想法是从Web应用程序向自身发出HTTP调用,使用与当前请求相同的端口号访问安全约束后面的路径,并从响应中解析重定向位置。当然,应缓存响应。是否有更直接的方法?

编辑:添加了一个包含这个想法代码的答案

2个回答

1
如果有人想知道如何实现我在问题中提出的想法,这里是我编写的一些示例代码进行测试。不过我认为我不会采用这个解决方案。
这适用于问题正文中的security-constraint块。
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;
}

-1

我不明白为什么你需要了解安全端口号。如果正在访问的资源被标记为需要 SSL,Tomcat 将会发送重定向到 https: 和相应的安全端口。这就是 server.xml 配置的作用。


嗨EJP,请考虑一个不安全的主页包含注册表单的情况(例如http://facebook.com,http://twitter.com)。如果不知道https端口(如果不是443),如何为表单操作生成https URL?Tomcat重定向是不够的,因为用户将在被重定向到安全URL之前未经安全地发布他/她的数据。 - andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接