在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:

Adding the signpost jars 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.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章