Android 通过 https ssl 方式连接服务端的配置方式

 
写android app, 通常需要与服务端通讯获取数据, 而这些数据的传输通常是通过HTTPS 协议来完成的,说白了也就是 http + ssl 来完成的, 从服务端的角度来说,与开发无关,只与application server 的配置相关, 下面的这个文档详细说明了,如何用android app 通过https 方式连接服务端.
 
工具介绍
Eclipse3.7
Tomcat 6.0.18(免安装版)
Android2.1开发环境(在Eclipse中配置好)
前提条件
JDK环境要使用我们自己安装的,笔者JDK安装目录为D:\Java\jdk1.6.0_22,在Eclipse的Window-preference-installed JREs中,只选用我们自己安装的JRE,如图所示:
在Eclipse与Tomcat整合的时候,也需要选择此运行环境:
 
 
 
 
一.搭建服务器端
1.在Eclipse中新建Dynamic Web Project,取名为HttpsServer:
2.index.jsp内容如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
 
<title>name+age JSP Page</title>
 
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
 
</head>
 
<body>
       <form action="/HttpsServer/TestService" method="get">
              name:&nbsp;<input name="name" type="text" /><br /> age: &nbsp;<input
                     name="age" type="text" /><br /> <input type="submit" value="submit" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input
                     type="reset" value="reset" />
       </form>
       <form action="/HttpsServer/TestService" method="post">
        name:&nbsp;<input name="name" type="text" /><br /> age: &nbsp;<input
            name="age" type="text" /><br /> <input type="submit" value="submit" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input
            type="reset" value="reset" />
    </form>
</body>
</html>
这里其实是复用了之前Http调研的代码,我们关心的是我们手机端能不能访问该服务器端,还涉及到传递数据,具体数据显示在TestService表示。
3.TestService代码如下:
package com.veer;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class TestService extends HttpServlet {
 
  
    private static final long serialVersionUID = 1L;
 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String name = req.getParameter("name");
        String age = req.getParameter("age");
 
        resp.setContentType("text/html");
 
        PrintWriter out = resp.getWriter();
 
        out.println("<html><head><title>name&age</title></head");
 
        out.println("<body> name:" + name + "<br>");
 
        out.println("age:" + age + "<br></body></html>");
 
        System.out.println("name=" + name);
        System.out.println("age=" + age);
        out.flush();
    }
 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String name = req.getParameter("name");
        String age = req.getParameter("age");
 
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8"); // 设置返回给客户端的文本格式,可解决文字编码不统一的问题
        PrintWriter out = resp.getWriter();
 
        out.println("<html><head><title>name&age</title></head");
 
        out.println("<body> name:" + name + "<br>");
 
        out.println("age:" + age + "<br></body></html>");
        System.out.println("name=" + name);
        System.out.println("age=" + age);
        out.flush();
    }
 
}
 
4.修改web.xml文件,在倒数第二行加入:
<servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>TestService</servlet-name>
    <servlet-class>com.veer.TestService</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>TestService</servlet-name>
    <url-pattern>/TestService</url-pattern>
  </servlet-mapping>
 
至此,未加密钥的服务器端就已经搭建好。
二.配置密钥
2.1 在D盘建立文件夹cer,再在里面建立文件夹tomcat;
2.2 进入cmd,依次键入cd\、d:、cd cer、cd tomcat,进入到D:\cer\tomcat目录下面;
2.3 生成服务器端密钥
键入D:\cer\tomcat>
keytool -genkey -alias tomcat -keyalg RSA -keystore server.keystore -validity 36000
解释:keytool是jdk下的命令行工具。
alias 随意指定,表示别名。keyalg表示加密算法为RSA,输出文件为server.keystore
这里面需要输入密码(我们输入123456),另外注意“您的名字与姓氏是什么?”,这一项要输入tomcat所在主机的IP或域名,客户端访问tomcat时会涉及到这个地址,笔者局域网的IP是192.168.1.213,所以我们输入该IP。
此时在D:\cer\tomcat里面就会生成一个server.keystore文件,不要关闭cmd,还有操作要进行;
 
2.4 用server.keystore生成server.cer
键入:D:\cer\tomcat>
keytool -export -alias tomcat -file server.cer -keystore server.keystore -storepass 123456
此时在D:\cer\tomcat里面就会生成一个server.cer文件。解释:这个是浏览器可以识别的证书,用于导入浏览器。
不要关闭cmd,还有操作要进行。
2.5 这个时候tomcat就可以启动ssl了,以tomcat6.0为例,在server.xml中拷入(或是更改)如下片段:
<Connector SSLEnabled="true" acceptCount="100" clientAuth="false" disableUploadTimeout="true" enableLookups="true" keystoreFile="D:/cer/tomcat/server.keystore" keystorePass="123456" maxSpareThreads="75" maxThreads="200" minSpareThreads="5" port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" secure="true" sslProtocol="TLS"/>
其中clientAuth="false" ,表示单向验证,为true的话则是双向认证。
 
这时启动tomcat,打开IE,输入https://192.168.1.213:8443/ 会提示没有证书,但能点进去。
我们可以双击刚才生成的server.cer,把它导入“受信任的根证书颁发机构”,就能看到浏览器上的小锁了。
 
三.特别说明
我们需要下载bcprov-jdk15-135.jar及sunjce_provider.jar(可能已经存在),放入D:\Java\jdk1.6.0_22\jre\lib\ext下面。同时要修改D:\Java\jdk1.6.0_22\j\jre\lib\security\java.security文件,
找到security.provider.1=sun.security.provider.Sun这行,这里有好几行,在最后一行加上security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider,笔者本来有9号,所以新一行的序号为10。
 
在cmd中继续键入:D:\cer\tomcat>
keytool -import -alias tomcat -file server.cer -keystore server_trust.keystore -storepass 123456 -storetype BKS -providername "BC"
这时候在D:\cer\tomcat里面就会生成一个server_trust.keystore文件。
解释:将在客户端用到这个信任的密钥。
 
 
四.搭建客户端
按照正常的步骤,我们建立一个Android Project,需要注意的是新建立一个文件夹res/raw,将server_trust.keystore拷贝至其中,在AndroidMainfest.xml中加入。如下图所示:
HttpsClientActivity 代码如下:
 
package com.veer;
 
import java.io.InputStream;
import java.security.KeyStore;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
 
public class HttpsClientActivity extends Activity {
    /** Called when the activity is first created. */
 
    private Button testButton;
    private String httpsUrl = "https://192.168.1.213:8443/HttpsServer/TestService";
    HttpClient hc = new DefaultHttpClient();
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        testButton = (Button) findViewById(R.id.testButton);
        testButton.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
                try {
                    initKey();
                } catch (Exception e) {
                    e.printStackTrace();
                }
 
                try {
                    String result = getData(httpsUrl);
                    System.out.println("result=" + result);
                } catch (Exception e) {
                    e.printStackTrace();
                }
 
            }
        });
    }
 
    private void initKey() throws Exception {
        KeyStore trustStore = KeyStore.getInstance("BKS");
        trustStore.load(
                getBaseContext().getResources().openRawResource(
                        R.raw.server_trust), "123456".toCharArray());
        SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
        Scheme sch = new Scheme("https", socketFactory, 8443);
        hc.getConnectionManager().getSchemeRegistry().register(sch);
 
    }
 
    private String getData(String url) throws Exception {
        HttpUriRequest hr = new HttpGet(url);
        HttpResponse hres = hc.execute(hr);
        HttpEntity he = hres.getEntity();
        InputStream is = he.getContent();
        StringBuffer sb = new StringBuffer();
        byte[] bytes = new byte[1024];
        for (int len = 0; (len = is.read(bytes)) != -1;) {
            sb.append(new String(bytes, 0, len, "utf-8"));
        }
        return sb.toString();
    }
}
 
 
 
main.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <Button
        android:id="@+id/testButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="HTTPS Test" />
 
</LinearLayout>
 
将该Android项目运行起来,点击按钮,在logcat中就可以看到打印信息:
在console控制台中可以看到信息:
至迟,手机端对https服务器简单的访问已经完成,至于其他的具体功能还要靠大家自己去扩展和封装。


除非申明,文章均为一号门原创,转载请注明本文地址,谢谢!
[本日志由 轻舞肥羊 于 2014-11-03 10:35 PM 编辑]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: Android ssl https
相关日志:
评论: 1 | 引用: 0 | 查看次数: -
回复回复天吧8[2015-01-07 11:31 AM | del]
app服务端采用ssl加密的项目有多大比例啊
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.