上篇提到picasso加载https图片说到了okhttp的单向验证问题,也就不解释啥叫单向认证了,先看一下谷歌的单向认证代码
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = AppContext.getInstance().getResources().openRawResource(R.raw.xxxxx);
Certificate ca;
try {
ca = cf.generateCertificate(in);
} finally {
in.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), new SecureRandom());
internalSSLSocketFactory = context.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
我一开始是这样写的,用的5.0以上的机子测试发现也能访问了,但是问题来了,4.4以下的机子死活访问不了,很无奈。上网查了一下说是4.4一下手机需要让其支持tsl1.1,tsl1.2,因此先创建一个类继承与SSLSocketFactory,然后重写一系列的方法,直接看代码吧
public class MySSL extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
// public X509TrustManager trustManager;
public MySSL(){
initSSL();
}
private void initSSL(){
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = AppContext.getInstance().getResources().openRawResource(R.raw.xxxxx);
Certificate ca;
try {
ca = cf.generateCertificate(in);
} finally {
in.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
/*TrustManager[] trustManagers=tmf.getTrustManagers();
if (trustManagers != null)
{
trustManager = new MyTrustManager(chooseTrustManager(trustManagers));
} else
{
trustManager = new UnSafeTrustManager();
}*/
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), new SecureRandom());
internalSSLSocketFactory = context.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
/*private static class UnSafeTrustManager implements X509TrustManager
{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[]{};
}
}*/
/* private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers)
{
for (TrustManager trustManager : trustManagers)
{
if (trustManager instanceof X509TrustManager)
{
return (X509TrustManager) trustManager;
}
}
return null;
}*/
/*private static class MyTrustManager implements X509TrustManager
{
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException
{
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
try
{
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce)
{
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
}*/
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
okhttp还需要设置一下X509TrustManager,所以只需要把代码中的注释去掉,将x509设置给okhttp就行了。试了下可以访问的通了。