繼續學習iOS,這個練習的Sina Weibo Demo。
這個練習程式將分多part實現。下面是第一篇 -- OAuth2.0認證。
下面還是要簡要說一下在程式開發之前的準備,首先要到新浪開發人員平台建立一個行動裝置 App獲得key和secret,注意還有一個要注意的是在管理中心的應用資訊裡的進階資訊中編輯OAuth2.0 授權設定的授權回調頁。
在認證這一部分會用到兩個API ,分別是請求授權和擷取授權。(連結地址是:http://open.weibo.com/wiki/Oauth2/authorize 和 http://open.weibo.com/wiki/OAuth2/access_token )。而這二者又是什麼關係呢?首先要通過authorize之後再拿到access token。而access
token是以後調用相關API的必要參數。在這兩個API的文檔中可以知道access token的調用參數中含有authorize調用後返回的code參數(具體看文檔)。
下面介紹authorize這個API。
https://api.weibo.com/oauth2/authorize?client_id=2909579077&redirect_uri=http://www.baidu.com&response_type=code&display=mobile&state=authorize
下面解釋一下這個URL是怎麼傳參的吧,首先是在認證url: https://api.weibo.com/oauth2/authorize的後面添加一個問號?然後傳遞各個參數和值,每個參數都是用&隔開。
參數說明:
其中client_id就是你申請建立應用的key;redirect_uri就是前面提到的在授權設定中的授權回調頁,注意要保持二者一致;response_type填寫code,這個code就是在授權的時候會返回的一串code,這一串code會在第二個API調用中作為參數值(注意:這個code是變化的,也就說每次授權的時候是動態變化的;而之後我們要擷取的access token這個是固定的),當然還可以填寫成token,那麼在授權返回的url地址中就包含了access
token(關於這個下面再詳述);display填寫mobile(移動終端應用);在最後的state這個參數是可選的,也就是或可以省去,加上後,在授權返回的資料中就包含這個參數項。那麼通過這個url,就可以在微博view中載入到一個授權頁面,可以通過瀏覽器輸入這個url驗證是否正確。
在授權後會得到的參數有:
傳回值欄位 |
欄位類型 |
欄位說明 |
code |
string |
用於調用access_token,介面擷取授權後的access token。 |
state |
string |
如果傳遞參數,會回傳該參數。 |
下面是載入webview的代碼,通過下面這段代碼就可以顯示授權頁。
- (void)viewDidLoad{ [super viewDidLoad];// Do any additional setup after loading the view, typically from a nib. NSString *urlString = @"https://api.weibo.com/oauth2/authorize?client_id=2909579077&redirect_uri=http://www.baidu.com&response_type=code&display=mobile&state=authorize"; NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; [self.webView setDelegate:self]; [_webView loadRequest:request]; }
上面authorize大概就是這樣了,那麼現在的問題是,如何擷取返回的資料呢?從官方API文檔中的樣本中,我們知道:授權後,會重新導向到另一個URL ,而這個URL中就包含了我們上面所說的要返回的資料(重點是code這個參數)。
下面先貼一段代碼,這個程式碼封裝含了擷取重新導向的URL,從這個URL中截取code參數值,將code這個參數值添加到access_token這個API後調用,調用後擷取返回的參數,對返回的參數進行處理進而擷取access_token。(所以這段代碼要處理的問題有點多)
第二個API access token調用的URL具體參考官方文檔和參看上文第一個API的URL。
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { NSURL *backURL = [request URL]; //接受重新導向的URL NSString *backURLString = [backURL absoluteString]; //判斷是否是授權調用返回的url if ([backURLString hasPrefix:@"http://www.baidu.com/?"]) { NSLog(@"back url string :%@",backURLString); //找到”code=“的range NSRange rangeOne; rangeOne=[backURLString rangeOfString:@"code="]; //根據他“code=”的range確定code參數的值的range NSRange range = NSMakeRange(rangeOne.length+rangeOne.location, backURLString.length-(rangeOne.length+rangeOne.location)); //擷取code值 NSString *codeString = [backURLString substringWithRange:range]; NSLog(@"code = :%@",codeString); //access token調用URL的string NSMutableString *muString = [[NSMutableString alloc] initWithString:@"https://api.weibo.com/oauth2/access_token?client_id=2909579077&client_secret=90184f4606fd04f449131ea4fbdb74c4&grant_type=authorization_code&redirect_uri=http://www.baidu.com&code="]; [muString appendString:codeString]; NSLog(@"access token url :%@",muString); //第一步,建立URL NSURL *urlstring = [NSURL URLWithString:muString]; //第二步,建立請求 NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:urlstring cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]; [request setHTTPMethod:@"POST"];//佈建要求方式為POST,預設為GET NSString *str = @"type=focus-c";//設定參數 NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; [request setHTTPBody:data]; //第三步,串連伺服器 NSData *received = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; NSString *str1 = [[NSString alloc]initWithData:received encoding:NSUTF8StringEncoding]; NSLog(@"Back String :%@",str1); //如何從str1中擷取到access_token NSDictionary *dictionary = [str1 objectFromJSONString]; NSLog(@"access token is:%@",[dictionary objectForKey:@"access_token"]); } return YES;}
這個程式啟動並執行結果
2013-04-14 15:46:14.798 OAuthDemo[350:c07] back url string :http://www.baidu.com/?state=authorize&code=a6146547f981199c07348837b0629d5d2013-04-14 15:46:14.799 OAuthDemo[350:c07] code = :a6146547f981199c07348837b0629d5d2013-04-14 15:46:14.799 OAuthDemo[350:c07] access token url :https://api.weibo.com/oauth2/access_token?client_id=2909579077&client_secret=90184f4606fd04f449131ea4fbdb74c4&grant_type=authorization_code&redirect_uri=http://www.baidu.com&code=a6146547f981199c07348837b0629d5d2013-04-14 15:46:15.059 OAuthDemo[350:c07] Back String :{"access_token":"2.00QF7O9Cn7SuKDdeaf7e6529rPILeC","remind_in":"157679999","expires_in":157679999,"uid":"2249439934"}2013-04-14 15:46:15.061 OAuthDemo[350:c07] access token is:2.00QF7O9Cn7SuKDdeaf7e6529rPILeC
下面對這段代碼進行解說一下:
1、首先我們在(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType 這個函數中接受授權重新導向後的URL。
2、但是這個函數在授權過程中可能會經過多次重新導向,而我們需要的是包含code參數的那個重新導向URL,所以要找到這個URL,我們是看他重新導向後的這個URL是否包含@"http://www.baidu.com/?"這個首碼,在包含的這個首碼的URL中就包含返回的資料(code)。
3、接著就是從這個URL中分離中出code的參數值。方法是這樣的,首先確定“code=”的range,然後由這個range再來確定code參數值的range,這樣就找到code的值了。
typedef struct _NSRange { NSUInteger location; NSUInteger length;} NSRange;DescriptionA structure used to describe a portion of a series—such as characters in a string or objects in an NSArray object.
4、code的參數值找到了,接下來就是對access token這個API 的調用了,採用的是同步POST請求。
5、最後的一步就是對access token這個API 呼叫返回的資料分離出access_token這個參數。
注意到這個api返回的參數
{ "access_token": "ACCESS_TOKEN", "expires_in": 1234, "remind_in":"798114", "uid":"12341234" }
這裡接收這些資料是放在string裡面,顯然這些是json類型,那麼這裡對其的處理是採用jsonkit這個第三方類庫,所以要匯入這個類庫,使用過程中可能會遇到ARC的問題,就是在ARC的項目工程中要對這個第三方類庫添加ARC的特性。
這裡使用的方法是
- (id)objectFromJSONString;把這些資料放到dictionary裡面方便分離出access_token.
完成,結合給出的程式運行結果應該可以理解了。