2 个问题的答案几乎不可能相同,因为我认为 TrustMananger 根本不会获得服务器的域名。
实际上,信任管理器可以获得您所追求的主机名的名称。不过,这取决于许多因素。
让我们假设您的客户端在 Java 7 上运行。
如果您遵循与其他答案相同的方法,但使用 an X509ExtendedTrustManager
(在 Java 7 中引入,而不是 plain X509TrustManager
),您将获得额外的重载方法,这些方法也为您提供当前的SSLSocket
或SSLEngine
。
使用实例SSLContext
初始化时会使用这些方法X509ExtendedTrustManager
,但当它是 plain 时不会使用X509TrustManager
,因此它必须在进行这些调用之前检查类型(请参阅此答案末尾的快速测试,基于该答案中的代码)。
我不确定这个行为是在哪里指定的 API。JSSE 参考指南中似乎没有关于这种X509ExtendedTrustManager
类型检查的任何内容。确保使用扩展方法的一种方法是在您的 . (这也是 Java 7 中引入的一个特性。)SSLParameters
从那里获得SSLSocket
或SSLEngine
获得,您可以获得SSLSession
和对等主机,因此您可以在那里执行检查。SSLSocket
(请注意,如果创建的库或未SSLEngine
使用将名称作为 a 传递的方法之一String
,而是通过 a代替,则主机名可能与预期不完全匹配InetAddress
。在这种情况下,您也会丢失 SNI。)
然后,您可以在默认情况下使用这样的信任管理器SSLContext
(使用setDefault(...)
)。
如果您不想影响默认值SSLContext
(这种调整的明智选择),您需要弄清楚您的客户端库如何在每个连接中使用不同的库。这完全取决于使用什么。
对于传统的URLConnection
,将其投射为一个HttpsURLConnection
并设置为SSLSocketFactory
您自定义的一个构建SSLContext
。
使用哪些方法取决于您是否实例化了 anX509ExtendedTrustManager
或 a X509TrustManager
:
X509TrustManager customTm = new X509ExtendedTrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return finalTm.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
System.out
.println("Current method: checkServerTrusted(chain, authType)");
finalTm.checkServerTrusted(chain, authType);
}
//@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType, Socket socket) throws CertificateException {
System.out
.println("Current method: checkServerTrusted(chain, authType, socket)");
finalTm.checkServerTrusted(chain, authType, socket);
}
//@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType, SSLEngine engine)
throws CertificateException {
System.out
.println("Current method: checkServerTrusted(chain, authType, engine)");
finalTm.checkServerTrusted(chain, authType, engine);
}
// Same for client-related methods.
};