原出处:https://my.oschina.net/8048/blog/661096
下面说下我项目的改善
1、把cer后缀的证书放在assets里面
/**
* 读取cer证书
*/
private void readCer(){
// 添加https证书
try {
InputStream is = getAssets().open("tomcat.cer");
NetConfig.addCertificate(is); // 这里将证书读取出来,,放在配置中byte[]里
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
2、NetConfig类
public class NetConfig {
// 证书数据
private static List<byte[]> CERTIFICATES_DATA = new ArrayList<>();
/**
* 添加https证书
* @param inputStream
*/
public synchronized static void addCertificate(InputStream inputStream) {
if (inputStream != null) {
try {
int ava = 0;// 数据当次可读长度
int len = 0;// 数据总长度
ArrayList<byte[]> data = new ArrayList<>();
while ((ava = inputStream.available()) > 0) {
byte[] buffer = new byte[ava];
inputStream.read(buffer);
data.add(buffer);
len += ava;
}
byte[] buff = new byte[len];
int dstPos = 0;
for (byte[] bytes:data) {
int length = bytes.length;
System.arraycopy(bytes, 0, buff, dstPos, length);
dstPos += length;
}
CERTIFICATES_DATA.add(buff);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* https证书
* @return
*/
public static List<byte[]> getCertificatesData() {
return CERTIFICATES_DATA;
}
}
3、验证证书后生成OkHttpClient
public static OkHttpClient createOkhttp() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// 添加证书
List<InputStream> certificates = new ArrayList<>();
List<byte[]> certs_data = NetConfig.getCertificatesData();
// 将字节数组转为数组输入流
if (certs_data != null && !certs_data.isEmpty()) {
for (byte[] bytes : certs_data) {
certificates.add(new ByteArrayInputStream(bytes));
}
}
SSLSocketFactory sslSocketFactory = getSocketFactory(certificates);
if (sslSocketFactory != null) {
builder.sslSocketFactory(sslSocketFactory);
}
//这很关键
OkHttpClient client = builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}).build();
return client;
}
/**
* 添加证书
*
* @param certificates
*/
private static SSLSocketFactory getSocketFactory(List<InputStream> certificates) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
try {
for (int i = 0, size = certificates.size(); i < size; ) {
InputStream certificate = certificates.get(i);
String certificateAlias = Integer.toString(i++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
if (certificate != null)
certificate.close();
}
} catch (IOException e) {
e.printStackTrace();
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init
(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
return sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
以上只是单向认证,需要后台服务器设置也是单向认证喔,认证成功后请求的接口参数就是乱码了,但能正常访问。