超级简单的retrofit使用自签名证书进行HTTPS请求的教程
1. 前言
HTTPS越来越成为主流,谷歌从 2017 年起,Chrome 浏览器将也会把采用 HTTP 协议的网站标记为「不安全」网站;苹果从 2017 年 iOS App 将强制使用 HTTPS;在国内热火朝天的小程序也要求必须使用 HTTPS 请求。那么为什么要使用HTTPS呢?首先说为什么使用https,简单点说就是为了防止数据传输过程中信息被窃取或偷换,防止中间人攻击。
2. 准备BKS证书,将证书放到项目raw目录下
准备.cer文件
可以跟后台开发人员直接拿,也可以直接在网站上下载
在网站上下载:
点击地址栏前面的小锁头,然后点击证书信息
将.cer转换为.bks
首先要下载bouncycastle的JAR
http://repo2.maven.org/maven2/org/bouncycastle/bcprov-jdk16/1.46/bcprov-jdk16-1.46.jar
解压后在当前文件夹执行以下命令
keytool -importcert -v -trustcacerts -file “server.cert” -alias server_alias -keystore “server.bks” -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath “bcprov-jdk16-146.jar” -storetype BKS -storepass password
黑体字部分是你要修改的,其中 “server.cert”是原cer证书的名字,“server_alias”你不用管,“server.bks”是转换后bks证书的名字,“password”是你证书的密码,下边会用到的。
成功后将.bks证书文件放到项目的raw目录下。
3. 获取SSLSocketFactory
这里是HTTPS证书认证的关键代码,注意password和设置keystore的bks类型一定不要搞错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/**
*
获取bks文件的sslsocketfactory
*
@param context
*
@return
*/ public static SSLSocketFactory
getSSLSocketFactory(Context context) {
final String
CLIENT_TRUST_PASSWORD = "123456" ; //信任证书密码,该证书默认密码是123456
final String
CLIENT_AGREEMENT = "TLS" ; //使用协议
final String
CLIENT_TRUST_KEYSTORE = "BKS" ;
SSLContext
sslContext = null ;
try {
//取得SSL的SSLContext实例
sslContext
= SSLContext.getInstance(CLIENT_AGREEMENT);
//取得TrustManagerFactory的X509**管理器实例
TrustManagerFactory
trustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//取得BKS密库实例
KeyStore
tks = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);
InputStream
is = context.getResources().openRawResource(R.raw.traint);
try {
tks.load(is,
CLIENT_TRUST_PASSWORD.toCharArray());
} finally {
is.close();
}
//初始化**管理器
trustManager.init(tks);
//初始化SSLContext
sslContext.init( null ,
trustManager.getTrustManagers(), null );
} catch (Exception
e) {
e.printStackTrace();
Log.e( "SslContextFactory" ,
e.getMessage());
}
return sslContext.getSocketFactory();
}
|
4.配置retrofit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
String
baseUrl = "https://skyish-test.yunext.com" ;
int []
certificates = {R.raw.traint};
String[]
hostUrls = {baseUrl};
OkHttpClient
client = new okhttp3.OkHttpClient.Builder()
.addInterceptor( new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.sslSocketFactory(HTTPSUtils.getSSLSocketFactory(context))
//.hostnameVerifier(HTTPSUtils.getHostNameVerifier(hostUrls))
.readTimeout( 10 ,
TimeUnit.SECONDS)
.connectTimeout( 10 ,
TimeUnit.SECONDS)
.build();
Retrofit
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(client)
.build();
|
配置好这个就可以使用HTTPS连接了。
5.常见错误
SSLContext is not initialized.
原因:
1. 证书和证书密码不匹配。
2. 使用了错误的证书。证书类型不对,记得要用bks格式的证书文件。