在Android实现客户端授权

OAuth对你的数据和服务正在变成实际上的允许访问协议在没有分享用户密码。实际上所有的有名公司像Twitter,Google,Yahoo或者LinkedIn已经实现了它。在所有流行的程序语言里有许多的库和代码例子也在你的d桌面程序,移动程序,或者web程序上实现了OAuth。

也有给Android的参考指南,然而他们中的大多数不是最新的,精确地或者在时间紧张的情况下理解是困难的。我们这里提供了几个容易的步骤来解释它怎么样用简单的方式完成它。

首先,简答描述OAuth是如何工作的。它是基于加密,加密的地方:

1.一个token和一个一致的密码,这个密码有客户端从服务端请求到。

2.这个token通过用户被验证作为有效和被允许访问他们的数据,然后

3.这个token被更新并且这个从那时候会被使用,直到通过相同的用户重新调用授权。

这个在第一步被请求的token被叫做request token.也就是说你通常指定了你想要访问的它服务的地方;它被叫做scope。第二步被叫做authorization,这一步是控制通过一个回调传回到客户应用程序。最后的token在第三步被接收叫做access token。这个能被使用很长时间,它不会过期(但是,正如提到的,用户能在任何时候调用它)。它是一个短字符串,用一个一直的密钥字符串,并且一旦应用程序请求它,它能被用于登录HTTP请求,为的是让供应商验证它。所有三步对供应商有一个一致的URL,对于一个HTTP请求被发送的地方获取token或者维护它。

如果你需要更深入的描述,在code.google.com上有一篇好文章使用API参照,并且还有用图非常详尽的概述。

我们将使用卓越的signpost的java库来实现OAuth访问到Gmail。只需要下载signpost-core和signpost-commonshttp4包,把他们复制到lib文件夹下,右键工程,在Properties/Java Build Path下你能把他们添加到build path中:

我们将实现OAuth支持通过一个背胶做OAUthHelper的帮助类。两个最重要的来被提供通过signpost的是OAuthConsumer和OAuthProvider,在跳到真正的连接以前,我们首先设置以下步骤:

private
OAuthConsumer mConsumer;

private
OAuthProvider mProvider;

private
String mCallbackUrl;

public
OAuthHelper(String consumerKey, String consumerSecret,

String
scope, String callbackUrl)

throws
UnsupportedEncodingException {

mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);

mProvider = new CommonsHttpOAuthProvider(

"https://www.google.com/accounts/OAuthGetRequestToken?scope="

+ URLEncoder.encode(scope, "utf-8"),

"https://www.google.com/accounts/OAuthGetAccessToken",

"https://www.google.com/accounts/OAuthAuthorizeToken?hd=default");

mProvider.setOAuth10a(true);

mCallbackUrl = (callbackUrl == null ? OAuth.OUT_OF_BAND : callbackUrl);

}

这个consumerKey和consumerSecret字符串依赖于你的客户端应用程序,你给两者能使用匿名。然后你也许想对供应商注册你的应用程序,它将发布一个key和一个密钥给你的APP,为了访问你一个用户的Gmail的收件范围是"https://mail.google.com/",这个授权的URLs是在帮助类的构造器中。

callbackUrl变量能被用于传递一个URL给供应商,一旦你的token被授权供应商将被调用。在Android中一旦验证完成,你能注册一个特别的URL框架到你的应用程序中,因此浏览器将触发一个你的app的activity。例如,如果你想要MyActivity被调用放到你的app的manifest中:

<activity
android:name="MyActivity">

<intent-filter>

<action
android:name="android.intent.action.VIEW"></action>

<category
android:name="android.intent.category.DEFAULT"></category>

<category
android:name="android.intent.category.BROWSABLE"></category>

<data
android:scheme="my-activity"></data>

</intent-filter>

</activity>

并且传递"my-activity://mywebsite.com/"最为一个回调URL。这也对你的应用程序的身份有影响作为mywebsite.com对供应商。你的应用程序将通过回调获得一个验证码作为给URL的查询参数,在这个URL中,查询key时"verifier"。你以后将需要这个。

public
String getRequestToken()

throws
OAuthMessageSignerException, OAuthNotAuthorizedException,

OAuthExpectationFailedException,
OAuthCommunicationException {

String authUrl = mProvider.retrieveRequestToken(mConsumer,

mCallbackUrl);

return authUrl;

}

In your OnResume() method in MyActivity you can catch the callback and retrieve the verifier, and upgrade your token with it:

String[] token = getVerifier();

if (token != null)

String accessToken[] = getAccessToken(token[1]);

...

private String[] getVerifier() {

// extract the token if it exists

Uri uri = this.getIntent().getData();

if (uri == null) {

return null;

}

String token = uri.getQueryParameter("oauth_token");

String verifier = uri.getQueryParameter("oauth_verifier");

return new String[] { token, verifier };

}

In our helper class:

public String[] getAccessToken(String verifier)

throws OAuthMessageSignerException, OAuthNotAuthorizedException,

OAuthExpectationFailedException, OAuthCommunicationException {

mProvider.retrieveAccessToken(mConsumer, verifier);

return new String[] {

mConsumer.getToken(), mConsumer.getTokenSecret()

};

}

And that‘s it. Just make sure you save the access token and its secret. You can now use signpost to sign your HTTP queries e.g.

OAuthConsumer consumer = new CommonsHttpOAuthConsumer(accessToken[0],

accessToken[1]);

HttpGet request = new HttpGet(url);

// sign the request

consumer.sign(request);

// send the request

HttpClient httpClient = new DefaultHttpClient();

HttpResponse response = httpClient.execute(request);

原文:

OAuth is becoming the de-facto protocol
to allow access to your data and services without sharing user password. Effectively all the big names such as Twitter, Google, Yahoo or LinkedIn have already implemented it. There are quite a few libraries and code samples in all the popular programming languages
out there to implement OAuth in your desktop, mobile or web application as well.

There are guides for
Android too, however most of them are not up to date, accurate or just difficult to comprehend if you are in a hurry. Here we provide a few easy to follow steps with some explanation how it can be done in a straightforward way.

First, a short summary how OAuth works. It is based on cryptography, where

  1. a token and a corresponding secret is acquired by a consumer (a desktop or web application)
    from a provider (a server in the cloud),
  2. this token is authorized by the user as valid and allowed to access their data and then
  3. the token is upgraded, and this can then be used from then on until it is revoked by same user who authorized it.

The token acquired in the first step is called a request token, this is where you usually specify which service you would like to get access to; it is called scope.
The second step is called authorization, after which control can be passed back to the consumer application via a callback. The final token that is received in the
third step is called access token. This can be used for a long period of time, it won‘t expire (but, as mentioned, the user can revoke it any time). It is basically
a short string, with a corresponding secret string, and once the application acquired it, it can be used to sign HTTP requests, thus authenticating it for the provider. All three steps have a corresponding URL at the provider, to where an HTTP request is sent
to get the token or manipulate it.

If you need further details, there‘s a good article with API reference at code.google.com,
and another very detailed overview with figures here.

We will use the excellent signpost Java
library to implement OAuth access to Gmail. Just download at
least the signpost-core and signpost-commonshttp4 jars, copy them to the lib/ folder inside your Android project, right click on the project, and under Properties/Java Build Path you can add them to the build path:

][]

We will implement OAuth support via a helper class called OAuthHelper. The two single most important classes provided by signpost are OAuthConsumer andOAuthProvider;
before diving into actual communications, we set these up first:

private OAuthConsumer mConsumer;
private OAuthProvider mProvider;
private String mCallbackUrl;
public OAuthHelper(String consumerKey, String consumerSecret,
String scope, String callbackUrl)
throws UnsupportedEncodingException {
    mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
    mProvider = new CommonsHttpOAuthProvider(
    "https://www.google.com/accounts/OAuthGetRequestToken?scope="
    + URLEncoder.encode(scope, "utf-8"),
    "https://www.google.com/accounts/OAuthGetAccessToken",
    "https://www.google.com/accounts/OAuthAuthorizeToken?hd=default");
    mProvider.setOAuth10a(true);
    mCallbackUrl = (callbackUrl == null ? OAuth.OUT_OF_BAND : callbackUrl);
}

The consumerKey and consumerSecret strings depend on your consumer
application, you can use anonymous for both. Later you might want to register your application at the provider (Google in this case), which will issue a key and secret for your app. To access an user‘s Gmail inbox the scope is"https://mail.google.com/",
the URLs for OAuth are in the constructor of the helper class.

The callbackUrl variable can be used to pass an URL to the provider which will be called once your token is authorized. On Android you can register a special URL
scheme to your application, thus the browser will fire up an activity of your app once authorization has been done. E.g. if you would like MyActivity to be called put the following
into your app manifest:

<activity android:name="MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="my-activity"></data>
</intent-filter>
</activity>

and pass "my-activity://mywebsite.com/" as the callback URL. This also has the side effect of identifying your application as mywebsite.com at
the provider (at least at Google). Your application will get back a verifier code via the callback as a query parameter to the URL, where the query key is "verifier". You will need
this later.

As a next step, retrieve the request token:

public String getRequestToken()
throws OAuthMessageSignerException, OAuthNotAuthorizedException,
OAuthExpectationFailedException, OAuthCommunicationException {
    String authUrl = mProvider.retrieveRequestToken(mConsumer,
    mCallbackUrl);
    return authUrl;
}

Once you got back the authentication URL from this method, just start up the browser with it:

try {
    String uri = helper.getRequestToken();
    startActivity(new Intent("android.intent.action.VIEW",
    Uri.parse(uri)));
} catch (...) {
}

In your OnResume() method in MyActivity you can catch the callback and retrieve the verifier, and upgrade
your token with it:

String[] token = getVerifier();
if (token != null)
String accessToken[] = getAccessToken(token[1]);
...
private String[] getVerifier() {
    // extract the token if it exists
    Uri uri = this.getIntent().getData();
    if (uri == null) {
        return null;
    }
    String token = uri.getQueryParameter("oauth_token");
    String verifier = uri.getQueryParameter("oauth_verifier");
    return new String[] { token, verifier };
}

In our helper class:

public String[] getAccessToken(String verifier)
throws OAuthMessageSignerException, OAuthNotAuthorizedException,
OAuthExpectationFailedException, OAuthCommunicationException {
    mProvider.retrieveAccessToken(mConsumer, verifier);
    return new String[] {
        mConsumer.getToken(), mConsumer.getTokenSecret()
    };
}

And that‘s it. Just make sure you save the access token and its secret. You can now use signpost to sign your HTTP queries e.g.

OAuthConsumer consumer = new CommonsHttpOAuthConsumer(accessToken[0],
accessToken[1]);
HttpGet request = new HttpGet(url);
// sign the request
consumer.sign(request);
// send the request
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);

Happy hacking!

Update: fixed some typos in code snippets.

时间: 2024-10-28 23:29:15

在Android实现客户端授权的相关文章

Android新浪微博客户端(七)——ListView中的图片异步加载、缓存

原文出自:方杰|http://fangjie.sinaapp.com/?p=193转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo 一.ListView的图片异步加载 我们都知道对每一个Weibo Item都有用户头像,而且每一条微博还可能带有图片.如果在加载列表的同时加载图片,这样有几个缺点,第一很费事,界面卡住,用户体验很不

Android新浪微博客户端(四)——添加多个账户及认证

原文出自:方杰| http://fangjie.sinaapp.com/?p=75 转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54 该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo 二.获取用户信息并保存数据库 上面说到加载AuthActivity有两种情况,其中一种就是授权成功回调,在授权回调成功后我们就开始通过微博API获取用户信息了,然后保存数据库了.这一系列操作我采

Android中客户端请求服务器端的方式讲解(一)附源码

Android中客户端请求服务器端的两种方式:Post方式和Get方式 在这里不直接赘述了,直接上源码如下: (1).Post的方式: /** * Post的请求方式 * * @param model * 请求序号 * @param paramList * 客户端请求的数据参数列表 * @return */ public JSONObject doPost(int model, List<NameValuePair> paramList) { try { // 客户端向服务器发送请求的数据 L

Android:解决客户端从服务器上获取数据乱码的方法

向服务器发送HTTP请求,接收到的JSON包为response,用String content = EntityUtils.toString(response.getEntity(),"utf-8");解码还是出现了中文乱码,在后面加了 String name = new String(response.getBytes("iso-8859-1"), "UTF-8"); 也无济于事.想到服务器好像是用URLENCODER编了码的,怀着试一试的态度

android多线程-客户端

预备知识: 一.android每个客户端分为两条线程: 1.主线程:负责生成主界面,并响应用户动作,并且把用户输入的数据写入socket对应的输出流. 2.子线程:负责读取从服务器发送过来的数据,并且显示到程序界面上. 二.Handler消息传递机制 (一)Handler的两个作用: 1.在新启动的线程中发送消息. 2.在主线程中获取.处理消息. (二)Handler相关的几个组件: 1.Message:Handler接收和处理的消息对象. 2.Looper:每个线程只能拥有一个Looper.

Android新浪微博客户端(六)——Home界面的ListView

原文出自:方杰|http://fangjie.sinaapp.com/?p=184转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo 一.首先是ListView的adapter. 因为微博列表的Item不是规则的,比如说有些微博有转发子微博,有些没有,有些有图片,有些没有图片,所以说很不固定.这里就采用BaseAdapter,要自

网易客户端授权密码,errormsg=&#39;authentication failed (method LOGIN)&#39; exitcode=EX_NOPERM

zabbix群里一网友在安装msmtp+mutt测试发送邮件失败 配置文件如下: /usr/local/msmtp/etc/msmtprc account default host smtp.163.com port 25 from [email protected]163.com auth login tls off user [email protected]163.com password xxxxx logfile /var/log/mmlog 测试发送的时候报错: [[email pr

开源:我的Android新闻客户端,速度快、体积小、支持离线阅读、操作简便、内容展现形式丰富多样、信息量大、功能全面 等(要代码的留下邮箱)

分享:我的Android新闻客户端,速度快.体积小.支持离线阅读.操作简便.内容展现形式丰富多样.信息量大.功能全面 等(要代码的留下邮箱) 历时30天我为了开发这个新闻客户端APP,以下简称觅闻 http://m.yunxunmi.com/ 由于本人比较愚钝,不太擅长各种开源代码的运用,因此全部从0开始开发,期间开发了: 一个新闻采集器(C++),截止目前为止已经连续运行20多天没出现任何故障,采集接近150个大中型新闻分类网站,采集器下载及介绍网站预计下周免费发布,风格类似我的即时通讯网站 

Android实践--Android Http 客户端编程之GET

Android Http 客户端编程之GET 说起Http编程,不尽然想起GET和POST两种请求方式,本文以简洁明了的的步骤和说明,将Android中常用的Http编程的方式列举出来,给刚刚在Android路上起步的奋斗者参考和指引,希望快速上手应用Android Http编程的同仁可以先绕过下面一段话. 做一件事之前,我们是否能驻足想一下要做这件事,我们需要做哪些工作,然后在经验中积累出模板思路和步骤,在程序界通常用设计模式来概括这些工作良好的解决方案.有了这些总结积累,这样我们就能举一反三