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類型一定不要搞錯。
/** * 獲取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
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格式的證書文件。