Java 如何提示用户接受或拒绝HTTPS证书?

Java 如何提示用户接受或拒绝HTTPS证书?,java,android,https,Java,Android,Https,我的Android应用程序使用DefaultHttpClient API向外部HTTP服务器发送请求。我无法切换到HTTPS 我的服务器使用自签名证书,默认情况下该证书显然不受信任 当应用程序连接到服务器时,我想向用户显示服务器证书的指纹,并让用户接受或拒绝证书 对于DefaultHttpClient,这可能吗?如果是的话,我可以看一段代码片段来说明它是如何完成的吗 我已经看到了许多解决这个问题和类似问题的假定解决方案,但没有一个对我有效。使用DefaultHTTPClient是不可能的,因为信

我的Android应用程序使用DefaultHttpClient API向外部HTTP服务器发送请求。我无法切换到HTTPS

我的服务器使用自签名证书,默认情况下该证书显然不受信任

当应用程序连接到服务器时,我想向用户显示服务器证书的指纹,并让用户接受或拒绝证书

对于DefaultHttpClient,这可能吗?如果是的话,我可以看一段代码片段来说明它是如何完成的吗


我已经看到了许多解决这个问题和类似问题的假定解决方案,但没有一个对我有效。

使用
DefaultHTTPClient是不可能的,
因为信任匹配发生在较低的级别,在SSL堆栈中(JSSE或OpenSSL或Android使用的任何东西)


最简单、最便宜的解决方案是根本不使用自签名证书。使用CA签名的证书。你已经花了超过它的成本,你将花更多的时间,它可能是值得的。把钱付给CA。

我终于找到了一个可行的解决方案。以下是片段:

public class MySocketFactory implements SocketFactory, LayeredSocketFactory {
private SSLContext mSslContext = null;

{
    try {
        mSslContext = SSLContext.getInstance("TLS");

        TrustManager trustManager = new X509TrustManager() {

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // NOTE : This is where we can calculate the certificate's fingerprint,
                // show it to the user and throw an exception in case he doesn't like it
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
            }
        };

        mSslContext.init(null, new TrustManager[]{ trustManager }, new SecureRandom());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public Socket connectSocket(Socket socket, String host, int port,
        InetAddress localAddress, int localPort, HttpParams params)
                throws IOException, UnknownHostException, ConnectTimeoutException {

    int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
    int soTimeout = HttpConnectionParams.getSoTimeout(params);

    SocketAddress socketAddress = new InetSocketAddress(localAddress, localPort);
    socket.bind(socketAddress);
    socket.connect(new InetSocketAddress(host, port), connTimeout);
    socket.setSoTimeout(soTimeout);

    return socket;
}

@Override
public Socket createSocket() throws IOException {
    return mSslContext.getSocketFactory().createSocket();
}

@Override
public boolean isSecure(Socket sock) throws IllegalArgumentException {
    return true;
}



@Override
public Socket createSocket(Socket socket, String host, int port,
        boolean autoClose) throws IOException, UnknownHostException {

    return mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
}

然后您可以像这样实例化DefaultHttpClient:

    HttpParams httpParameters = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpParameters, 5000);
    DefaultHttpClient result = new DefaultHttpClient(httpParameters);


    MySocketFactory mySocketFactory = new MySocketFactory();
    Scheme scheme = new Scheme("https", mySocketFactory, port);

    result.getConnectionManager().getSchemeRegistry().register(scheme);

我试过了,它确实有效

“我见过很多解决这个问题和类似问题的方法,但没有一种对我有效”——列出它们并解释你遇到的具体问题。下次我尝试失败时,我会在这里发布具体的问题。问题是昨晚我尝试了几种不同的方法,但没有一种对我有效,在我厌倦了之后,我就懒得记下每种假设的解决方案。你说“这不可能”是因为你知道这是事实还是仅仅因为你不知道答案?我这样问是因为我已经知道如何让DefaultHttpClient使用应用程序的自定义密钥库,其中信任匹配也发生在较低的级别,所以您提供的原因并不能完全说服我。此外,我的应用程序将与用户的个人、支持DynDNS的Raspberry Pi服务器一起使用,因此不可能提前知道使用了哪个证书。这就是为什么我希望用户能够通过指纹接受或拒绝。