豆瓣api之OAuth認證

豆瓣api經過OAuth容許第三方應用訪問用戶數據,因此OAuth認證就是咱們整個project的基礎了。web

OAuth認證聽起來挺神祕,其實挺簡單的。windows

如今的大型網站的開放平臺的認證幾乎都是採用OAuth,好比facebook,twitter,新浪微博等。api

豆瓣的api有對於OAuth認證的專門說明:http://www.douban.com/service/apidoc/auth服務器

在你使用OAuth認證以前,先仔細讀一讀文檔很是有必要,由於中間過程出現一點誤差,你就不能被認證成功,因此仔細閱讀官方文檔是重中之重:http://oauth.net/documentation/spec/網絡

若是你的英文不夠給力的話,能夠看看這篇中文的介紹,說的很清楚:http://www.supidea.com/post/oauth.aspxapp

google OAuth項目已經提供了OAuth的各類語言的庫:http://code.google.com/p/oauth/異步

咱們正式使用了google OAuth中的C#庫: http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cside

由於OAuth已經成爲了第三方開發者使用豆瓣api的一大障礙,豆瓣曾經專門舉辦了一次活動來說解如何經過OAuth使用豆瓣api:http://www.douban.com/online/10012959/svn

此次活動的源碼在google code上能夠找到:http://code.google.com/p/douban-oauth-sample/,咱們正式參考了http://code.google.com/p/douban-oauth-sample/source/browse/trunk/csharp/DoubanOAuthBasicSample/DoubanOAuthBasicSample/Program.cs這個文件,對咱們的幫助很大,省去了不少摸索的時間函數

做爲命令行程序咱們已經測試成功了,可是當移植到windows phone上以後就出現了問題

問題的關鍵在於silverlight版的網絡方面的api和C#的不一樣,silverlight的api更少,這就致使了上面的庫的一些網絡訪問要本身改寫

仔細閱讀httpwebrequest的文檔後,咱們發現,要進行一個網絡請求,至少要三個函數,由於須要使用兩次異步請求(BeginGetRequestStream,BeginGetResponse)

由於咱們的豆瓣app幾乎每一個動做都要對豆瓣服務器進行請求,若是每一個請求都須要寫三個函數,而且還要增長認證信息的話,實在是太麻煩,代碼會變得又臭又長

這時候DRY(don’t repeat yourself)就顯得尤其重要了

做爲pm,我決定把網絡訪問這一塊封裝好,給你們提供統一的,簡單好用的藉口。

我本準備本身把那兩個異步請求封裝起來,後來發現已經有現成的庫可用,並且很好很強大。

這個庫就是restsharp:http://restsharp.org/

並且restsharp還提供了windows phone對應的dll,非常方便,原來的三個函數如今只須要一個函數幾行就能夠搞定

對於不少請求,豆瓣都要求有認證才能夠訪問,根據豆瓣的文檔「進行POST、PUT、DELETE請求時,豆瓣暫時不支持使用在url中或者post form中傳遞OAuth參數。所以你只能選擇在header中傳遞OAuth參數」,看來咱們只能把oauth加到http header中了。

我部分我統一封裝了一下:
namespace AddOAuthHeader{
    public class OAuthHeader{
        string apiKey = "your api key";
        string apiKeySecret = "your api key secret";
        string accessToken;
        string accessTokenSecret;
        string uri;
        string method;
        OAuthBase oAuth = new OAuthBase();
        IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;

        public OAuthHeader(string uri, string method) {
            this.uri = uri;
            this.method = method;
        }

        public string getHeader(){
            string nonce = oAuth.GenerateNonce();
            string timeStamp = oAuth.GenerateTimeStamp();
            string normalizeUrl, normalizedRequestParameters;

            //accessToken = settings["accessToken"].ToString();
            //accessTokenSecret = settings["accessTokenSecret"].ToString();

            accessToken = "ee7ead643e6ea1a1cb7c082cbb4be4e3";
            accessTokenSecret = "545138430a2dcc9b";

            string sig = oAuth.GenerateSignature(
                new Uri(uri),
                apiKey,
                apiKeySecret,
                accessToken,
                accessTokenSecret,
                method,
                timeStamp,
                nonce,
                OAuthBase.SignatureTypes.HMACSHA1,
                out normalizeUrl,
                out normalizedRequestParameters);
            sig = HttpUtility.UrlEncode(sig);

            StringBuilder oauthHeader = new StringBuilder();
            oauthHeader.AppendFormat("OAuth realm=\"\", oauth_consumer_key={0}, ", apiKey);
            oauthHeader.AppendFormat("oauth_nonce={0}, ", nonce);
            oauthHeader.AppendFormat("oauth_timestamp={0}, ", timeStamp);
            oauthHeader.AppendFormat("oauth_signature_method={0}, ", "HMAC-SHA1");
            oauthHeader.AppendFormat("oauth_version={0}, ", "1.0");
            oauthHeader.AppendFormat("oauth_signature={0}, ", sig);
            oauthHeader.AppendFormat("oauth_token={0}", accessToken);

            return oauthHeader.ToString();
        }
    }
}

傳入一個url和一個方法(post or put or delete or get),我就給他返回一個oauth header,其餘同窗直接調用個人代碼就行了,並不須要關心認證問題

那具體該如何來進行一個網絡請求呢?

我寫了兩個例子,一個post的,一個get的。

向豆瓣傳數據,post:(我把說明都寫到了註釋中)

// "POST" 實例,以發一條狀態爲例
private void button1_Click(object sender, RoutedEventArgs e)
{
    //首先都要先實例化一個OAuthHeader,傳入的參數爲url和網絡請求的方法(post or get or delete or put or something else)
    OAuthHeader header = new OAuthHeader("http://api.douban.com/miniblog/saying", "POST");

    //對於post,要傳給服務器一些數據,豆瓣api用xml來傳數據,就須要先build一個xml的string
    StringBuilder requestBody = new StringBuilder("<?xml version='1.0' encoding='UTF-8'?>");
    requestBody.Append("<entry xmlns:ns0=\"http://www.w3.org/2005/Atom\" xmlns:db=\"http://www.douban.com/xmlns/\">");
    requestBody.Append("<content>hello world</content>");
    requestBody.Append("</entry>");

    //下面兩行是每個網絡請求都須要的,即與api.douban.com創建一個鏈接
    var client = new RestClient();
    client.BaseUrl = "http://api.douban.com";

    //下面這行的意思是產生一個請求,第一個參數是路徑名(不是完整的url),後面是Method.POST 或 Method.GET 或Method.PUT 或 Method.DELETE
    var request = new RestRequest("/miniblog/saying", Method.POST);

    //下面進行一些http頭的設置

    //先設置request的format爲xml
    request.RequestFormat = DataFormat.Xml;
    request.AddHeader("Content-Type", "application/atom+xml");

    //而後是把生成的authorization寫入http的header
    request.AddHeader("Authorization", header.getHeader());

    //最終把要上傳的數據寫入http請求中,注意要加上ParameterType.RequestBody
    request.AddParameter("application/atom+xml", requestBody.ToString(), ParameterType.RequestBody);

    //最後就是進行異步網絡請求了,而且將傳回的response的信息解析出來,呈如今頁面上
    client.ExecuteAsync(request, (response) =>
    {
        var resource = response.Content;
        Debug.WriteLine(resource);
    });
}

 

//GET實例,以獲取好友列表爲例,get比較簡單,不須要傳入數據
private void button3_Click(object sender, RoutedEventArgs e)
{
    //同上
    OAuthHeader header = new OAuthHeader("http://api.douban.com/people/34788764/contacts?start-index=1&max-results=50", "GET");

    var client = new RestClient();
    client.BaseUrl = "http://api.douban.com";

    //注意,這裏生成request的時候,不要把?後面的parameter加上,parameter要在後面的request.AddParameter處實現
    var request = new RestRequest("/people/34788764/contacts", Method.GET);

    //加上認證頭
    request.AddHeader("Authorization", header.getHeader());

    //加上參數
    request.AddParameter("start-index", "1");
    request.AddParameter("max-results", "50");

    client.ExecuteAsync(request, (response) =>
    {
        var resource = response.Content;
        Debug.WriteLine(resource);
        textBlock1.Text = resource;
    });
}

這樣就能夠大大簡化網絡請求,真正作到了don’t repeat yourself

相關文章
相關標籤/搜索