一、HTTPS介绍
简单讲是HTTP的安全版。
背景: HTTP大势已去 HTTPS加密挑大梁 2017年苹果APP强制HTTPS:苹果公司从2017年1月1日起将全面强制要求iOS App使用HTTPS加密连接。只有HTTPS的网站才能通过iOS App安全审核。
SSL协议(Secure Socket layer)
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
工作流程:
HTTPS操作:
Android模拟器和Tomcat服务器之间的HTTPS数据交互:
生成一对非对称加密的密钥对(公钥和私钥)
私钥交给服务器,公钥交给客户端
1.生成服务器使用的https.jks
keytool -genkeypair -alias itheima -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore
https.jks
2.在tomcat服务器中配置Https
tomcat/config/server.xml修改connector配置
<Connector
port="8443"
protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="conf/itheima.jks"
keystorePass="123456"/>
访问:https://127.0.0.1:8443/Shop2hService/home
表示用浏览器Https访问服务器成功
3.从keystore中导出证书(公钥androidHttps.jks)
1.浏览器导出证书方式
2.命令行方式:
keytool -exportcert -alias itheima -file itheima.cer -keystore https.jks -storepass 123456
4.Android端https请求实现
/**
* https请求封装
*
* @author christ
*/
public class HttpUtil {
public static String get(String url) throws Exception {
HttpURLConnection connection = (HttpURLConnection)
new URL(url).openConnection();
connection.connect();
if (connection.getResponseCode() == 200) {
return stream2String(connection.getInputStream());
} else {
return "not 200";
}
}
public static String get(String url, InputStream stream, String alias) throws Exception {
if (url.startsWith("https://")) { // https新增代码
HttpsURLConnection.setDefaultSSLSocketFactory(getSocketFactory(stream, alias));
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // 主机名校验通过
}
});
}
return get(url);
}
/**
* 初始化https配置
*/
public static SSLSocketFactory getSocketFactory(
InputStream cerStream, String alias) throws Exception {
// (1)创建Certificate证书
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(cerStream);
// (2)创建KeyStore,并指定证书
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null); // 清空默认证书
ks.setCertificateEntry(alias, cert);
// (3)创建TrustManager信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(ks);
TrustManager[] tm = trustManagerFactory.getTrustManagers();
// (4)创建SSLContext对象,并指定信任管理器对象
SSLContext sslContext = SSLContext.getInstance("TLS");
// 指定本地的证书
sslContext.init(null, tm, null);
// 信任所有的证书
// sslContext.init(null, new TrustManager[]{new MyTrustManager()}, null);
// (5)设置SSLSocketFactory对象
return sslContext.getSocketFactory();
}
/** 信任所有的证书 */
private static class MyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
}
/**
* 流转换成String
*/
public static String stream2String(InputStream is) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = -1;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
String result = baos.toString("utf-8");
is.close();
baos.close();
return result;
}
}
2.HTTPUrlConnection的用法
private String url = "https://10.0.0.2:8443/Shop2hService/home";
private int keystoreId = R.raw.androidHttps; // 数字证书
private void getData01() {
new Thread() {
public void run() {
try {
InputStream stream = getResources().openRawResource(keystoreId);
final String result = HttpUtil.get(url, stream, "");
showContent("HttpURLConnect: \n" + result);
} catch (final Exception e) {
...
}
}
}.start();
}
3.OKHttp用法
private void getData02() {
try {
InputStream isCert = getResources().openRawResource(keystoreId);
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
if (url.startsWith("https://")) {
okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(HttpUtil.getSocketFactory(isCert, "alias"))
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
System.out.println("------hostname: " + hostname);
return true;
}
}).build();
}
Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
...
} catch (Exception e) {
e.printStackTrace();
}
}
4.Retrofit的用法
/**
* Retrofit初始化
*/
public void initRetrofit() {
// OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
//
// //创建拦截器对象
// HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
//
// //设置拦截器对象的级别
// loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//
// //设置okhttpClient的日子拦截器,作用,打印请求和响应数据,设置拦截时间
// builder.addInterceptor(loggingInterceptor).connectTimeout(20, TimeUnit.SECONDS);
try {
InputStream isCert = Global.mContext.getResources().openRawResource(androidHttps);
OkHttpClient mClient = new OkHttpClient.Builder().build();
if (IRetrofitAPI.HOST_URL.startsWith("https://")) {
mClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder1 = request.newBuilder();
Request build = builder1.addHeader("userid", SharedPreUtil.getString("userid", "")).build();
return chain.proceed(build);
}
}).retryOnConnectionFailure(true)
.sslSocketFactory(HttpUtil.getSocketFactory(isCert, "http"))
// .addInterceptor(loggingInterceptor).connectTimeout(20, TimeUnit.SECONDS)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}).build();
}
mRetrofit = new Retrofit
.Builder()
.baseUrl(IRetrofitAPI.HOST_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(mClient)
// .client(builder.build())
.build();
mIRetrofitAPI = mRetrofit.create(IRetrofitAPI.class);
} catch (Exception e) {
e.printStackTrace();
}
}
最后模拟器也能把数据打印出来。
扩展