繼上次Apache伺服器憑證申請與安裝後,就可以開始implement了
這時你的Web Server已經有經過CA認可的合法憑證,且是在有效的效期內,因此可以直接參考Security with HTTPS and SSL
寫完你的APP就可以透過https和你的Server溝通了......好講解完畢,你已經可以和Server用https連線了
.
.
.
不過這裡當然不會講一般正常的情況下,而是當你沒有錢買憑證的時後,卻又想要你的app能透過https和你的server溝通
這時後又該怎麼做呢???
通常不用錢的憑證就只有自己當CA,自己產生自簽憑證(self-signed certificate)一途了
而這種情況有兩種做法來讓你的APP信任自簽憑證,一種是比較危險,另外一種是危險中比較安全一點的
為何兩個都說危險呢? 因為信任非CA認可過的憑證本身就是很危險的一件事了
但雖如此還是會有情況下是需要強制允許的 (本人就有這個需求)
而第一種危險中似乎比較安全一點的作法,我沒研究,因為我覺得很「費氣」
它的做法是把你認為合法的憑證,預先先放到你的APP裡,然後連線的時後直接拿local端的憑證去驗
所以下開始講第二種方法,也就是強制允許所有自簽憑證(很危險,請斟酌使用)
首先Android要透過https與Server溝通有兩種寫法,使用HttpsURLConnection或HttpClient
HttpsURLConnection是2.3之後才出現的package,也是Android Developer建議的新的使用方式
曾有看過一篇google裡面工程師的一篇文章,他提到舊有的HttpClient由於提供很多很細的API
每次Upgrade的時後都要費很多工來維護,而HttpsURLConnection已經提供大部分一般Programer會用到的API
因此漸漸的他們想要用HttpsURLConnection來取代HttpClient
所以本來我也想用HttpsURLConnection來實作upload,但後來發現我沒辦法及時的取得目前檔案上傳幾個byte~
因為上傳的這個動作底層都幫我做掉了,我只能把要上傳的資料塞給API,之後就不歸我管一直等到Server回應成功或失敗
但也許是我還沒找到方法取得及時的上傳API,有知道方法的網友再請指教分享一下囉~
以下還是要先說明使用HttpsURLConnection要如何才能強制允許所有自簽憑證,至於HttpClient會再另開一篇解說
我想,開始說HttpsURLConnection前也不用解釋太多,直接看Code吧:
try{
URL url = new URL("https://127.0.0.1/weblogin.php");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//AllowAllHostNameVerifier
HttpsURLConnection.setDefaultHostnameVerifier(new AllowAllHostNameVerifier());
// Create the SSL connection
SSLContext sc;
sc = SSLContext.getInstance("TLS");
//The following are the most important to allow self-signed certificate
sc.init(null, new TrustManager[] {
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
}
}, null);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
// set Timeout and method
conn.setReadTimeout(20000);
conn.setConnectTimeout(7000);
conn.setRequestProperty("Content-Length", String.valueOf(args.getBytes().length));
java.io.DataOutputStream dos = new java.io.DataOutputStream(conn.getOutputStream());
dos.writeBytes(args);
java.io.BufferedReader rd = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = rd.readLine()) != null) {
content.append(line);
}
rd.close();
responseContent = content.toString();
System.out.println(responseContent);
} catch (Exception e) {
e.printStackTrace();
tv.setText(e.toString());
}
下面則是實作用來騙APP說Server端驗證沒問題的Class
public class AllowAllHostNameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
//Log.i("RestUtilImpl", "Approving certificate for " + hostname);
System.out.println("RestUtilImpl Approving certificate for " + hostname);
return true;
}
}
Place your comment