如果你自己想做一个客户端玩玩,但是又不想去搭建后台服务器,显然Bmob移动后端云是你的最佳选择。官方地址见bmob,文档地址见http://www.bmob.cn/docs。他提供了Android的sdk,同样也提供了Restful Api,但是个人建议Restful Api还是不适合直接在客户端使用,毕竟会暴露一下一些key的信息,但是本篇文章就是在android中使用它的restful api,原因嘛很简单,我想网络层自己控制,不想用它提供的android sdk,对于安全方面,同样给出了这种情况的解决方法。

新建应用

首先你得有个账号,然后你得有个应用,具体内容见http://docs.bmob.cn/restful/faststart/index.html?menukey=fast_start&key=start_restful

编写代码

我们使用OkHttp,还需要用到Gson,增加依赖

    compile 'com.squareup.okhttp:okhttp:2.5.0'compile 'com.google.code.gson:gson:2.3.1'

增加网络访问权限

    <uses-permission android:name="android.permission.INTERNET"/>

编写一个网络的请求,插入一条数据

实体类

public class Person {private String name;private String address;private int age;public Person(String name, String address, int age) {this.name = name;this.address = address;this.age = age;}public Person() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", address='" + address + '\'' +", age=" + age +'}';}
}

进行请求,这部分代码是java平台的,在android上你需要开启一个线程。

private static final String URL_INSERT ="https://api.bmob.cn/1/classes/Person";
private static final String APPLICATION_ID="8dcb9fee2f******14ab19e7dfd9d";
private static final String API_KEY="aebe3b71c9b2***********430ac2de560b1";
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final Gson gson=new Gson();
private static final OkHttpClient client=new OkHttpClient();
Person person=new Person("张三","杭州",20);
RequestBody body = RequestBody.create(JSON, gson.toJson(person));
Request insert=new Request.Builder().url(URL_INSERT).addHeader("Content-Type","application/json").addHeader("X-Bmob-Application-Id", APPLICATION_ID).addHeader("X-Bmob-REST-API-Key",API_KEY).post(body).build();
try {Response execute = client.newCall(insert).execute();System.out.println(execute.body().string());
} catch (IOException e) {e.printStackTrace();
}

注意请求头里面的几个参数,必须设置。

这时候如果你进行请求,你会发现会报一个异常

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

原来是https请求,我们需要获得证书。

当然这时候你有两个选择,一个是信任所有证书。

public class MyX509TrustManager  implements X509TrustManager {public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public X509Certificate[] getAcceptedIssuers() {return null;}
}try {  // 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] tm = { new MyX509TrustManager() };SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();client.setSslSocketFactory(ssf);
} catch (NoSuchAlgorithmException e) {e.printStackTrace();
} catch (NoSuchProviderException e) {e.printStackTrace();
} catch (KeyManagementException e) {e.printStackTrace();
}

但是这种方法有安全隐患,我们还是使用证书吧。

首先用Chrome打开https://api.bmob.cn/,然后点击链接左边的锁的图形,切到连接项,点击证书信息,如下图

然后将证书导出即可,之后一直下一步即可。

这里假设导出的证书名字为bmob.cer,将其放到assets目录下。

然后编写一个https验证的工具类。


/*** User:lizhangqu(513163535@qq.com)* Date:2015-09-23* Time: 17:45*/
public class SSLUtil {//使用命令keytool -printcert -rfc -file srca.cer 导出证书为字符串,然后将字符串转换为输入流,如果使用的是okhttp可以直接使用new Buffer().writeUtf8(s).inputStream()/*** 返回SSLSocketFactory** @param certificates 证书的输入流* @return SSLSocketFactory*/public static SSLSocketFactory getSSLSocketFactory(InputStream... certificates) {return getSSLSocketFactory(null,certificates);}/*** 双向认证* @param keyManagers KeyManager[]* @param certificates 证书的输入流* @return SSLSocketFactory*/public static SSLSocketFactory getSSLSocketFactory(KeyManager[] keyManagers, 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());trustManagerFactory.init(keyStore);sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom());SSLSocketFactory socketFactory = sslContext.getSocketFactory();return socketFactory;} catch (Exception e) {e.printStackTrace();}return null;}/*** 获得双向认证所需的参数* @param bks bks证书的输入流* @param keystorePass 秘钥* @return KeyManager[]对象*/public static KeyManager[] getKeyManagers(InputStream bks, String keystorePass) {KeyStore clientKeyStore = null;try {clientKeyStore = KeyStore.getInstance("BKS");clientKeyStore.load(bks, keystorePass.toCharArray());KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());keyManagerFactory.init(clientKeyStore, keystorePass.toCharArray());KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();return keyManagers;} catch (KeyStoreException e) {e.printStackTrace();} catch (UnrecoverableKeyException e) {e.printStackTrace();} catch (CertificateException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}
}

如果你不想使用文件,则你可以导出证书的内容,使用命令进行导出

keytool -printcert -rfc -file bmob.cer

然后将其赋值给一个字符串

private static final String CERT="-----BEGIN CERTIFICATE-----\n" +"MIIGLjCCBRagAwIBAgIDFCb6MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJJTDEWMBQGA1UE\n" +"ChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln\n" +"bmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3MgMSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2\n" +"ZXIgQ0EwHhcNMTQxMTA3MDExNzM0WhcNMTUxMTA4MDIxMDQ2WjBJMQswCQYDVQQGEwJDTjEUMBIG\n" +"A1UEAxMLYXBpLmJtb2IuY24xJDAiBgkqhkiG9w0BCQEWFWhlc2hhb3l1ZUBmb3htYWlsLmNvbTCC\n" +"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANCEvBFYJmhW+8iixdK0zlzwprsuytUGW5BH\n" +"ye9EEkJzGzYfVnEO/v4wC3vEvlWqkwTxY/ydnneH+yo0msAN6IEt6IA+3eO55PAlooAF8b8I2e83\n" +"usRTK4YmooZc/2GYNk2WBXvVlMuWABMKJ/oQMXlM46gffd3Z+evbbptZ5vm+QEWjUlw8fsTALakq\n" +"JgKsrmGSNBVngx1qnm00DL/3yfR2DZHro4CDzRp4toQV3ofcnt6Nz43Z4YkAXZr5gqxge8BZ2n8P\n" +"raQo/5wSfWoPW79Z8lPvZSZv5UIGCUAXdt0qYb3awSDsPSnMrRl03V4XmOK3RDdYDPrWMvii+YrC\n" +"/vUCAwEAAaOCAtkwggLVMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUF\n" +"BwMBMB0GA1UdDgQWBBR8ztcEh/lE/9fxcga6p7/b+x+pUTAfBgNVHSMEGDAWgBTrQjTQmLCrn/Qb\n" +"awj3zGQu7w4sRTAfBgNVHREEGDAWggthcGkuYm1vYi5jboIHYm1vYi5jbjCCAVYGA1UdIASCAU0w\n" +"ggFJMAgGBmeBDAECATCCATsGCysGAQQBgbU3AQIDMIIBKjAuBggrBgEFBQcCARYiaHR0cDovL3d3\n" +"dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjCB9wYIKwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2Vy\n" +"dGlmaWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRoaXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBh\n" +"Y2NvcmRpbmcgdG8gdGhlIENsYXNzIDEgVmFsaWRhdGlvbiByZXF1aXJlbWVudHMgb2YgdGhlIFN0\n" +"YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25seSBmb3IgdGhlIGludGVuZGVkIHB1cnBvc2Ug\n" +"aW4gY29tcGxpYW5jZSBvZiB0aGUgcmVseWluZyBwYXJ0eSBvYmxpZ2F0aW9ucy4wNQYDVR0fBC4w\n" +"LDAqoCigJoYkaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMIGOBggrBgEFBQcB\n" +"AQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20vc3ViL2NsYXNzMS9z\n" +"ZXJ2ZXIvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2NlcnRzL3N1Yi5j\n" +"bGFzczEuc2VydmVyLmNhLmNydDAjBgNVHRIEHDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8w\n" +"DQYJKoZIhvcNAQELBQADggEBAF/t9Bc14BV0OwXcFf4Bs8y+p1AdbMqualCvLzjS95Z9HbPGcbRl\n" +"W76XwaM7iFE1R4mR1lGBQsacbBHOCNeZURYWGAG5c/yqhqCmWCzVJxM88AhCzkEv98uKa3IqE1zY\n" +"lOpYn4cMVqpPgg47QXqUfQlRoh21UTTORgiHEUY+JYNIlIXLoHtHVR0886+pIAq5fFrCwMHF45Df\n" +"r8tuTASazhYJUlOiGQTVv5p8Kg1wJ0ftMs9xJpThcnpEWrngmnNH/8H05rvJ9dEHkpnAU4mL46Bb\n" +"rmQe3oNoGE5EISL9KGVUMeS9wcR2kx+VmGhnAh7kjn5KuEidgfajS3XlcJ5o9t0=\n" +"-----END CERTIFICATE-----";

然后使用OkIO里的Buffer类进行读取并设置

SSLSocketFactory sslSocketFactory = SSLUtil.getSSLSocketFactory(new Buffer().writeUtf8(CERT).inputStream());
client.setSslSocketFactory(sslSocketFactory);

当然之前我们已将将其放到assets目录下了,就不用这么麻烦的导出字符串,赋值等操作,我们之间使用该文件即可

try {SSLSocketFactory sslSocketFactory = SSLUtil.getSSLSocketFactory(getAssets().open(CERT_FILENAME));client.setSslSocketFactory(sslSocketFactory);} catch (IOException e) {e.printStackTrace();
}

这时候你请求一下,就会发现可以成功请求了,并且服务器返回了信息

请求的问题解决了,那么还遗留了一个重要的问题,就是如果使用Restful API,我们的APPLICATION_ID和API_KEY就直接暴露在客户端了。有没有一种方法可以提高一定的安全性呢,方法是有的,只不过只是相对来说安全一点,但是如果人家想搞你,那也是没有办法的,方法就是使用jni获得这两个值,由jni层返回这两个字符串。

Android Studio下ndk的开发环境搭建见Android Studio使用新的Gradle构建工具配置NDK环境,这里不再累赘。

声明java层方法

public class KeyUtil {static {System.loadLibrary("key");}public static native String getApplicationId();public static native String getAPIKey();
}

使用alt+enter生成jni方法,并在里面返回这两个值

#include <jni.h>JNIEXPORT jstring JNICALL
Java_cn_edu_zafu_bmobdemo_util_KeyUtil_getApplicationId(JNIEnv *env, jclass instance) {char returnValue[]="8dcb9fe*************ab19e7dfd9d";return (*env)->NewStringUTF(env, returnValue);
}JNIEXPORT jstring JNICALL
Java_cn_edu_zafu_bmobdemo_util_KeyUtil_getAPIKey(JNIEnv *env, jclass instance) {char returnValue[]="aebe3b71c9b*****************e560b1";return (*env)->NewStringUTF(env, returnValue);
}

在java层要获得这两个值只要使用对应的静态方法即可。

KeyUtil.getApplicationId();
KeyUtil.getAPIKey();

最终,我们的代码也就成了这样子


public class MainActivity extends AppCompatActivity {private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");private static final String URL ="https://api.bmob.cn/1/classes/Person";private static final String CERT_FILENAME ="bmob.cer";private static final Gson gson=new Gson();private static final OkHttpClient client=new OkHttpClient();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {SSLSocketFactory sslSocketFactory = SSLUtil.getSSLSocketFactory(getAssets().open(CERT_FILENAME));client.setSslSocketFactory(sslSocketFactory);} catch (IOException e) {e.printStackTrace();}Person person=new Person("张三","杭州",20);RequestBody body = RequestBody.create(JSON, gson.toJson(person));Request insert=new Request.Builder().url(URL).addHeader("Content-Type","application/json").addHeader("X-Bmob-Application-Id", KeyUtil.getApplicationId()).addHeader("X-Bmob-REST-API-Key",KeyUtil.getAPIKey()).post(body).build();client.newCall(insert).enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {}@Overridepublic void onResponse(Response response) throws IOException {Log.e("TAG",response.body().string());}});}});}}

这种方法只能提高一定的安全性但是不能完全避免,人家只要反汇编你的so就能看到这两个值,你要再加强安全性就只能在jni层进行加密解密等操作了,总之就是不要直接返回字符串。

之后你在Bmob后台就能看到数据

Bmob为懒人提供了很好的后端解决方案,我们几乎不用写一句代码,就可以搭建一个强大的后台服务。

最后放上源码。
http://download.csdn.net/detail/sbsujjbcy/9135981

Android使用Bmob移动后端云Restful API需要注意的问题相关推荐

  1. Android之Bmob移动后端云服务器

    源码下载:http://download.csdn.net/download/jjhahage/10034519 PS:一般情况下,我们在写android程序的时候,想要实现登录注册功能,可以选择自己 ...

  2. android中bmob云存储,Android中的Bmob移动后端云服务器功能

    PS:一般情况下,我们在写android程序的时候,想要实现登录注册功能,可以选择自己用servlet作为服务端来实现过滤没有注册过的用户,但是太麻烦,而且不是随时都可以用的.这里介绍一个移动后端云服 ...

  3. Bmob移动后端云服务平台

    Bmob移动后端云服务平台--Android从零开始--(二)android快速入门 上一篇博文我们简单介绍何为Bmob移动后端服务平台,以及其相关功能和优势.本文将利用Bmob快速实现简单例子,进一 ...

  4. Bmob 移动后端云服务器平台实现登录注册

    源码下载:http://download.csdn.net/download/jjhahage/10034519 PS:一般情况下,我们在写android程序的时候,想要实现登录注册功能,可以选择自己 ...

  5. jwt配置 restful_SpringBoot实现JWT保护前后端分离RESTful API

    本文将用不到100行Java代码, 教你如何在Spring Boot里面用JWT保护RESTful api. 登录前 登录之后即可得到正确结果 登陆后 1. 什么是JWT 了解JWT的同学可以跳过这一 ...

  6. bmob php,文档-Bmob移动后端云服务平台

    Q:php为什么添加数据的时候字段的值为中文就会出错 A:检查下你的php编码,建议改为utf-8编码. Q:有没有ts的sdk A:php的sdk只有一个 Q:使用PHP CURL 推送消息的代码, ...

  7. bmob项目php后端,bmob开发文档-Bmob移动后端云服务平台

    容器服务快速入门 简介 您可以把代码部署到Bmob容器上运行. 目前容器支持PHP和Java的语言环境. 你可以将整个网站架设在Bmob容器之上,提供了网站托管服务. 只需要完成下面的两步,你就可以使 ...

  8. android bmob获取密码,Bmob后端云初体验

    声明:作者原创,转载注明出处. 一.Baas简介 Baas,Backend as a Service的简称,即"移动后端即服务". "移动后端即服务"是移动平台 ...

  9. Bmob关联Android,Android如何使用Bmob后端云实现失物招领功能

    最近在使用后端云Bmob对数据进行存储,目的是在不搭建服务器的前提下,能对Android应用的数据进行操作处理,其实这篇是比较久之前写的了,有些童鞋反馈说现在的源码会有问题,所以我又重新运行了一下,随 ...

最新文章

  1. Ubuntu系统安装搜狗输入法详细教程
  2. 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序 3
  3. MobileNetV3
  4. Testing for SSL renegotiation
  5. 使用ABBYY FineReader进行自动图像预处理
  6. 使用Spring Boot和MongoDB构建一个反应式应用程序
  7. mysql数据库设计三大范式_数据库设计三大范式详解
  8. MTK A/B system说明及配置
  9. iOS最为简单时间轴(GZTimeLine)
  10. “听话”的苏宁少东家
  11. Centos 下tomcat环境搭建
  12. mschart控件使用详解
  13. jrtplib linux编译,linux下jrtplib-3.9.1编译与安装.txt
  14. Phase2 Day10 Tree3Set
  15. 计算机学院静态网页毕业论文,静态网页毕业论文静态网页毕业论文.doc
  16. MapReduce实现商品推荐算法(用户购买向量*商品同现矩阵)
  17. 企业微信应用授权/静默登录
  18. 解封ChatGPT我只用了一句话
  19. 【UOJ】UER#3.B 开学前的日历
  20. 华为手机设置信息服务器地址,华为手机如何设置云服务器地址

热门文章

  1. python 读取gmail 邮箱消息
  2. matebook13 java开发_紧急要跑程序?华为 MateBook X Pro一键搞定立马进状态
  3. Linux使用ffmpeg添加水印,ffmpeg视频随机添加水印
  4. 判断两个单向链表是否相交
  5. 算法:next数组的求法详解
  6. 蓝牙模块 hc06 linux,HC-06蓝牙模块设置和使用方法
  7. 智能网联云控平台在园区自动驾驶的场景应用
  8. 博图——推荐大家组个双屏
  9. 爬取网易云音乐两万条评论储存在MySQL服务器上
  10. 16S扩增子分析专题课01背景介绍