mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e)
{
e.printStackTrace();
}
}
为了代码可读性,我把异常捕获的部分简化了,可以看到我们提供了一个方法传入InputStream流,InputStream就对应于我们证书的输入流。
代码内部,我们:
-
构造CertificateFactory对象,通过它的
generateCertificate(is)
方法得到Certificate。 -
然后讲得到的
Certificate
放入到keyStore中。 -
接下来利用keyStore去初始化我们的
TrustManagerFactory
-
由
trustManagerFactory.getTrustManagers
获得TrustManager[]
初始化我们的SSLContext
-
最后,设置我们mOkHttpClient.setSslSocketFactory即可。
这样就完成了我们代码的编写,其实挺短的,当客户端进行SSL连接时,就可以根据我们设置的证书去决定是否新人服务端的证书。
记得在Application中进行初始化:
public class MyApplication extends Application
{
@Override
public void onCreate()
{
super.onCreate();
try
{
OkHttpClientManager.getInstance()
.setCertificates(getAssets().open(“srca.cer”));
} catch (IOException e)
{
e.printStackTrace();
}
}
然后尝试以下代码访问12306的网站:
OkHttpClientManager.getAsyn(“https://kyfw.12306.cn/otn/”, new OkHttpClientManager.ResultCallback()
{
@Override
public void onError(Request request, Exception e)
{
e.printStackTrace();
}
@Override
public void onResponse(String u)
{
mTv.setText(u);
}
});
这样即可访问成功。完整代码已经更新至:https://github.com/hongyangAndroid/okhttp-utils,可以下载里面的sample进行测试,里面包含12306的证书。
ok,到这就可以看到使用Okhttp可以很方便的应对自签名的网站的访问,只需要拿到包含公钥的证书即可。
(二)、使用字符串替代证书
下面继续,有些人可能觉得把证书copy到assets下还是觉得不舒服,其实我们还可以将证书中的内容提取出来,写成字符串常量,这样就不需要证书根据着app去打包了。
zhydeMacBook-Pro:temp zhy$ keytool -printcert -rfc -file srca.cer
-----BEGIN CERTIFICATE-----
MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn
BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X
DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp
bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3
DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2
9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6
D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle
tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov
LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt
x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV
23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ
og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A==
-----END CERTIFICATE-----
使用keytool
命令,以rfc样式输出。keytool
命令是JDK里面自带的。
有了这个字符串以后,我们就不需要srca.cer这个文件了,直接编写以下代码:
public class MyApplication extends Application
{
private String CER_12306 = “-----BEGIN CERTIFICATE-----\n” +
“MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn\n” +
“BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X\n” +
“DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp\n” +
“bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3\n” +
“DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2\n” +
“9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6\n” +
“D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle\n” +
“tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov\n” +
“LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt\n” +
“x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV\n” +
“23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ\n” +
“og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A==\n” +
“-----END CERTIFICATE-----”;
@Override
public void onCreate()
{
super.onCreate();
OkHttpClientManager.getInstance()
.setCertificates(new Buffer()
.writeUtf8(CER_12306)
.inputStream());
}
注意Buffer是okio包下的,okhttp依赖okio。
ok,这样就省去将cer文件一起打包进入apk了。
接下来介绍,如何去生成证书以及在tomcat服务器下使用自签名证书部署服务。如果大家没这方面需要可以简单了解下。
四、tomcat下使用自签名证书部署服务
首先自行下载个tomcat的压缩包。
既然我们要支持https,那么肯定需要个证书,如何生成证书呢?使用keytool非常简单。
(一)生成证书
zhydeMacBook-Pro:temp zhy$ keytool -genkey -alias zhy_server -keyalg RSA -keystore zhy_server.jks -validity 3600 -storepass 123456
您的名字与姓氏是什么?
您的组织单位名称是什么?
您的组织名称是什么?
您所在的城市或区域名称是什么?
您所在的省/市/自治区名称是什么?
该单位的双字母国家/地区代码是什么?
CN=zhang, OU=zhang, O=zhang, L=xian, ST=shanxi, C=cn是否正确?
输入 <zhy_server> 的密钥口令
(如果和密钥库口令相同, 按回车):
使用以上命令即可生成一个证书请求文件zhy_server.jks
,注意密钥库口令为:123456
.
接下来利用zhy_server.jks
来签发证书:
zhydeMacBook-Pro:temp zhy$ keytool -export -alias zhy_server
-file zhy_server.cer
-keystore zhy_server.jks
-storepass 123456
即可生成包含公钥的证书zhy_server.cer
。
(二)、配置Tomcat
找到tomcat/conf/sever.xml
文件,并以文本形式打开。
在Service标签中,加入:
<Connector SSLEnabled=“true” acceptCount=“100” clientAuth=“false”
disableUploadTimeout=“true” enableLookups=“true” keystoreFile=“” keystorePass=“123456” maxSpareThreads=“75”
maxThreads=“200” minSpareThreads=“5” port=“8443”
protocol=“org.apache.coyote.http11.Http11NioProtocol” scheme=“https”
secure=“true” sslProtocol=“TLS”
/>
注意keystoreFile的值为我们刚才生成的jks文件的路径:/Users/zhy/ temp/zhy_server.jks
(填写你的路径).keystorePass值为密钥库密码:123456
。
然后启动即可,对于命令行启动,依赖环境变量JAVA_HOME;如果在MyEclispe等IDE下启动就比较随意了。
启动成功以后,打开浏览器输入url:https://localhost:8443/
即可看到证书不可信任的警告了。选择打死也要进入,即可进入tomcat默认的主页:
如果你在此tomcat中部署了项目,即可按照如下url方式访问:
https://192.168.1.103:8443/项目名/path
,没有部署也没关系,直接拿默认的主页进行测试了,拿它的html字符串。
对于访问,还需要说么,我们刚才已经生成了zhy_server.cer
证书。你可以选择copy到assets,或者通过命令拿到内部包含的字符串。我们这里选择copy。
依然选择在Application中设置信任证书:
public class MyApplication extends Application
{
private String CER_12306 = “省略…”;
@Override
public void onCreate()
{
super.onCreate();
try
{
OkHttpClientManager.getInstance()
.setCertificates(
new Buffer()
.writeUtf8(CER_12306).inputStream(),
getAssets().open(“zhy_server.cer”)
);
} catch (IOException e)
{
e.printStackTrace();
}
}
}
ok,这样就能正常访问你部署的https项目中的服务了,没有部署项目的尝试拿https://服务端ip:8443/
测试即可。
注意:不要使用localhost,真机测试保证手机和服务器在同一局域网段内。
ok,到此我们介绍完了如果搭建https服务和如何访问,基本上可以应付极大部分的需求了。当然还是极少数的应用需要双向证书验证,比如银行、金融类app,我们一起来了解下。
五、双向证书验证
首先对于双向证书验证,也就是说,客户端也会有个“kjs文件”,服务器那边会同时有个“cer文件”与之对应。
我们已经生成了zhy_server.kjs
和zhy_server.cer
文件。
接下来按照生成证书的方式,再生成一对这样的文件,我们命名为:zhy_client.kjs
,zhy_client.cer
.
(一)配置服务端
首先我们配置服务端:
服务端的配置比较简单,依然是刚才的Connector标签,不过需要添加些属性。
<Connector 其他属性与前面一致
clientAuth=“true”
truststoreFile=“/Users/zhy/temp/zhy_client.cer”
/>
将clientAuth
设置为true,并且多添加一个属性truststoreFile,理论上值为我们的cer文件。这么加入以后,尝试启动服务器,会发生错误:Invalid keystore format
。说keystore的格式不合法。
我们需要对zhy_client.cer执行以下步骤,将证书添加到kjs文件中。
keytool -import -alias zhy_client
-file zhy_client.cer -keystore zhy_client_for_sever.jks
接下里修改server.xml为:
<Connector 其他属性与前面一致
clientAuth=“true”
truststoreFile=“/Users/zhy/temp/zhy_client_for_sever.jks”
/>
此时启动即可。
此时再拿浏览器已经无法访问到我们的服务了,会显示基于证书的身份验证失败
。
我们将目标来到客户端,即我们的Android端,我们的Android端,如何设置kjs文件呢。
(二)配置app端
目前我们app端依靠的应该是zhy_client.kjs
。
ok,大家还记得,我们在支持https的时候调用了这么俩行代码:
sslContext.init(null, trustManagerFactory.getTrustManagers(),
new SecureRandom());
mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
注意sslContext.init的第一个参数我们传入的是null,第一个参数的类型实际上是KeyManager[] km
,主要就用于管理我们客户端的key。
于是代码可以这么写:
public void setCertificates(InputStream… certificates)
{
try
{
CertificateFactory certificateFactory = CertificateFactory.getInstance(“X.509”);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates)
{
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try
{
if (certificate != null)
certificate.close();
} catch (IOException e)
{
}
}
SSLContext sslContext = SSLContext.getInstance(“TLS”);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
文末
架构师不是天生的,是在项目中磨练起来的,所以,我们学了技术就需要结合项目进行实战训练,那么在Android里面最常用的架构无外乎 MVC,MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。
一线互联网Android面试题总结含详解(初级到高级专题)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
tManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
文末
架构师不是天生的,是在项目中磨练起来的,所以,我们学了技术就需要结合项目进行实战训练,那么在Android里面最常用的架构无外乎 MVC,MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。
[外链图片转存中…(img-rZY6lEo4-1714126013685)]
[外链图片转存中…(img-Kjjc9Qew-1714126013685)]
一线互联网Android面试题总结含详解(初级到高级专题)
[外链图片转存中…(img-qLoJN2Ml-1714126013685)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!