SDK地址
点此下载最新版SDK这篇文章具体谈谈在iOS上如何通过新浪微博账户登录应用。
在讨论这个之前,不得不说到OAuth。这是个什么玩意呢?按照官方的说法,OAuth是:An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.
大概意思是说OAUTH是一种开放的协议,为桌面程序或者基于BS的web应用提供了一种简单的,标准的方式去访问需要用户授权的API服务。
也就是说,通过OAuth,应用或者网站服务可以获取用户的授权,但又不会获取到用户的账户信息(比如登录名和密码)。这里的授权包括:允许向用户发送某些信息,允许向用户提供访问网站的权限等等。
其实,对于大部分应用来说,只需要验证用户是否属于新浪微博用户,如果属于,那也自动是我的用户,如果不属于,那么请用户就地注册一个账户。换句话说,你将新浪微博的几亿用户自动承认成为你的网站用户,而不需要这几亿用户通过注册才能使用你的应用。所以,这是典型的一种YY思想,YY你瞬间获得了几亿用户!!
既然OAuth是一个协议,那么就需要用编程语言去实现它。目前,各种版本的OAuth基本都可以在google code下载到,包括C,C++,C#,JS,PHP等等。当然,肯定会有objective-C,否则,我也不会写这篇文章了。
OK,假设已经有了一个版本的Objective-C的OAuth的实现。下面就利用它来实现微博账户在iOS上的登录。
第一步:注册应用。
可以通过新浪微博的开放平台去注册一个应用。之后你会得到一个App Key和一个App Secret。拥有它们,你才可以申请权限。
假设你的App Key是“1234567890”,App Secret是“abcdefghijklmnopqrstuvwxyz”
第二步:写代码。
将获取到的OAuth的objective-C版本加入你的project中。将你申请到的Key和Secret做为两个变量定义并赋值。
对于OAuth来说,很多细节不需要我们去关注的,只要知道几个重要的步骤即可:
1. 创建一个request,这个request包含key和secret的信息,用于向新浪微博申请获得对应用户的权限。
2. 通过request向新浪微博发出请求,告诉新浪微博说:我是一个合法的注册过的应用,现在准备向大人您申请获得用户的权限,请您高抬贵手。
3. 获得未授权的 Request Key。这个获得未授权的 Request Key就相当于放行条,也就是新浪微博允许你开始获取用户的权限。
4. 根据这个Request Key的内容,获得一个url地址,这个地址页面就是想登录你应用的用户输入用户名和密码的地方。注意的是,这个url是属于新浪微博为你的这个应用创建的,是属于新浪微博的。调用iOS的接口,从浏览器打开这个url界面。
5. 用户在上述登录界面输入自己的用户名和密码,成功登录之后(其实是新浪微博认证此用户是注册了新浪微博的用户),你可以获得已授权的 Access KEY。这个Access Key就包含了用户多登录信息(包括昵称、用户ID等等,这里的昵称是指用户显示在新浪微博上的名字,而不是用户的登录名)。
6. 到目前为止,你已经确定用户是新浪微博的用户了,自然也是你的应用的用户(继续YY),所以接下去,你就赶紧允许用户登录成功,进入你的应用主界面,享受你的应用程序了。还愣着干嘛,翠花,上酸菜!!
找到一个objective-c实现的OAuth,并且对着每一步(第六步除外,第六步是在你自己的project中实现。你总不能让OAuth给你上酸菜吧),找到实现每一步功能的函数,然后加入你自己的project中。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
#import <Foundation/Foundation.h>
@interface SinaCodePathAndDic : NSObject + ( NSString * )writeToFilePath; + ( NSMutableDictionary * )code; @end #import "SinaCodePathAndDic.h" @implementation SinaCodePathAndDic + ( NSString * )writeToFilePath { NSString *fileName = [NSHomeDirectory ( ) stringByAppendingPathComponent : @ "tmp/sinacode.plist" ]; return fileName; } + ( NSMutableDictionary * )code { NSString *fileName = [NSHomeDirectory ( ) stringByAppendingPathComponent : @ "tmp/sinacode.plist" ]; NSMutableDictionary * codeDic = [ NSMutableDictionary dictionaryWithContentsOfFile :fileName ]; return codeDic; } @end #import <Foundation/Foundation.h> #define SinaAppkey @"309949296" #define SinaAppSecret @"a86376995071dc71a8616035c3d89176" #define SinaCOMEBACK_URL @"http://www.m-bao.com" #define URL_Authorize @"https://api.weibo.com/oauth2/authorize" 使用浏览器授权request token (这个url加上参数在浏览器执行) #define URL_Access @"https://api.weibo.com/oauth2/access_token" //获取access token #define URL_SHARE_TEXT @"http://api.t.sina.com.cn/statuses/update.json" #define URL_SHARE_PIC @"https://api.weibo.com/2/statuses/upload.json" #define TOKEN_USER_ID @"token_userId" #define TOKEN_PREFIX @"token_weibo" #define TOKEN_PROVIDER @"token_sina" #import <Foundation/Foundation.h> #import <CommonCrypto/CommonDigest.h> @interface SinaShareURL : NSObject { } - ( id )initWithText : ( NSString * )text_; - ( id )initWithText : ( NSString * )text_ andPic : (UIImage * )pic_; + ( BOOL )isDic; @end #import "SinaShareURL.h" #import "SinaKey.h" #import "SinaToken.h" #import "URLEncode.h" #import "JSON.h" #define SHAREURL @"https://api.weibo.com/2/statuses/repost.json" @implementation SinaShareURL + ( BOOL )isDic { NSDictionary * DIC = [ NSDictionary dictionaryWithDictionary : [SinaToken userDataAndToken ] ]; if ( ! [DIC valueForKey : @ "access_token" ] ) { return NO; } return YES; } - ( id )initWithText : ( NSString * )text_ { NSDictionary * DIC = [ NSDictionary dictionaryWithDictionary : [SinaToken userDataAndToken ] ]; NSURL * url_ = [ NSURL URLWithString : [ NSString stringWithFormat : @ "https://api.weibo.com/2/statuses/update.json?access_token=%@", [DIC valueForKey : @ "access_token" ] ] ]; NSString * str_ = [ NSString stringWithFormat : @ "status=%@", [URLEncode encodeUrlStr :text_ ] ]; NSData * data = [str_ dataUsingEncoding :NSUTF8StringEncoding ]; NSMutableURLRequest * request = [ NSMutableURLRequest requestWithURL :url_ ]; [request setHTTPMethod : @ "POST" ]; [request setHTTPBody :data ]; [ NSURLConnection connectionWithRequest :request delegate :self ]; return self; } - ( id )initWithText : ( NSString * )text_ andPic : (UIImage * )pic_ { NSDictionary * DIC = [ NSDictionary dictionaryWithDictionary : [SinaToken userDataAndToken ] ]; NSURL * url_ = [ NSURL URLWithString : [ NSString stringWithFormat : @ "https://api.weibo.com/2/statuses/upload.json?access_token=%@", [DIC valueForKey : @ "access_token" ] ] ]; NSMutableURLRequest * request = [ NSMutableURLRequest requestWithURL :url_ ]; UIImage * image_ = pic_; NSData * imgData_ = UIImageJPEGRepresentation (image_, 0 ); NSString *boundary = @ "AAAVVVAAA"; NSString *boundaryEnd = [ NSString stringWithFormat : @ "\r\n--%@--\r\n",boundary ]; NSString *Content_Type = [ NSString stringWithFormat : @ "multipart/form-data; boundary=%@",boundary ]; NSMutableString *bodyString = [ NSMutableString stringWithCapacity : 100 ]; [bodyString appendFormat : @ "--%@",boundary ]; [bodyString appendString : @ "\r\nContent-Disposition: form-data; name="status "\r\n\r\n" ]; if (text_ ) { [bodyString appendString : [URLEncode encodeUrlStr :text_ ] ]; } else { [bodyString appendString : [URLEncode encodeUrlStr : @ " " ] ]; } [bodyString appendFormat : @ "\r\n--%@",boundary ]; [bodyString appendString : @ "\r\nContent-Disposition: form-data; name="pic "; filename="image.jpg "\r\nContent-Type: image/jpeg\r\n\r\n" ]; //data NSMutableData *bodyDataWithPic = [ NSMutableData dataWithData : [bodyString dataUsingEncoding :NSUTF8StringEncoding ] ]; [bodyDataWithPic appendData :imgData_ ]; [bodyDataWithPic appendData : [boundaryEnd dataUsingEncoding :NSUTF8StringEncoding ] ]; //set header [request setValue :Content_Type forHTTPHeaderField : @ "Content-Type" ]; [request setValue : [ NSString stringWithFormat : @ "%d", [bodyDataWithPic length ] ] forHTTPHeaderField : @ "Content-Length" ]; [request setHTTPBody :bodyDataWithPic ]; [request setHTTPMethod : @ "POST" ]; [ NSURLConnection connectionWithRequest :request delegate :self ]; return self; } - ( void )connection : ( NSURLConnection * )connection didReceiveData : ( NSData * )data { NSString * str = [ [ NSString alloc ] initWithData :data encoding :NSUTF8StringEncoding ]; NSLog ( @ "asd=%@", [str JSONValue ] ); // NSLog(@"111%@",data); } - ( void )connectionDidFinishLoading : ( NSURLConnection * )connection { // NSString * str = [[NSString alloc] initWithData:data_ encoding:NSUTF8StringEncoding]; // NSLog(@"asd=%@",[str JSONValue]); [UIApplication sharedApplication ].networkActivityIndicatorVisible = NO; } @end #import <Foundation/Foundation.h> @protocol SinaTokenDeletage <NSObject> - ( void )tokenSaveOkayForSina; @end @interface SinaToken : NSObject { NSMutableData * data; id<SinaTokenDeletage>deletage; } @property (nonatomic,assign ) id<SinaTokenDeletage>deletage; - ( void )getToken; - ( void )removeToken; + ( NSString * )writeToFilePath; + ( NSMutableDictionary * )userDataAndToken; @end #import "SinaToken.h" #import "SinaUrl.h" #import "JSON.h" @implementation SinaToken @synthesize deletage; - ( void )dealloc { if (data ) { [data release ]; } [super dealloc ]; } + ( NSString * )writeToFilePath { NSString *fileName = [NSHomeDirectory ( ) stringByAppendingPathComponent : @ "tmp/sinauser.data" ]; return fileName; } + ( NSMutableDictionary * )userDataAndToken { NSString *fileName = [NSHomeDirectory ( ) stringByAppendingPathComponent : @ "tmp/sinauser.data" ]; NSData * data = [ NSData dataWithContentsOfFile :fileName ]; NSString * dataStr = [ [ NSString alloc ] initWithData :data encoding :NSUTF8StringEncoding ]; NSMutableDictionary * userDic = [dataStr JSONValue ]; NSLog ( @ "%@",userDic ); return userDic; } - ( void )getToken { data = [ [ NSMutableData alloc ] init ]; NSURL * url_ = [ NSURL URLWithString : [SinaUrl SinaGetToKenURLString ] ]; NSLog ( @ "cc=%@", [SinaUrl SinaGetToKenURLString ] ); NSMutableURLRequest * request = [ NSMutableURLRequest requestWithURL :url_ ]; [request setHTTPMethod : @ "POST" ]; [ NSURLConnection connectionWithRequest :request delegate :self ]; } - ( void )connection : ( NSURLConnection * )connection didReceiveData : ( NSData * )_data { // NSLog(@"22222%@",data); [data appendData :_data ]; } - ( void )connectionDidFinishLoading : ( NSURLConnection * )connection { NSLog ( @ "!!!!!!!!!!!%@,",data ); NSString *fileName = [NSHomeDirectory ( ) stringByAppendingPathComponent : @ "tmp/sinauser.data" ]; NSLog ( @ "%@,",data ); [data writeToFile :fileName atomically : YES ]; if (deletage ) { [deletage tokenSaveOkayForSina ]; } } - ( void )removeToken { NSFileManager * fileManager = [ NSFileManager defaultManager ]; NSString *fileName = [NSHomeDirectory ( ) stringByAppendingPathComponent : @ "tmp/sinauser.data" ]; [fileManager removeItemAtPath :fileName error : nil ]; NSLog ( @ "%@",fileName ); } @end #import <Foundation/Foundation.h> #import "SinaKey.h" @interface SinaUrl : NSObject { } + ( NSString * )SinaUrlString; + ( NSString * )SinaGetToKenURLString; //+(NSString *)SinaShareUrlString; @end #import "SinaUrl.h" #import "SinaCodePathAndDic.h" @implementation SinaUrl + ( NSString * )SinaUrlString { NSString * parameter = @ ""; NSMutableArray * urlArray = [ [ NSMutableArray alloc ] init ]; [urlArray addObject : [ NSString stringWithFormat : @ "client_id=%@",SinaAppkey ] ]; [urlArray addObject : [ NSString stringWithFormat : @ "redirect_uri=%@",SinaCOMEBACK_URL ] ]; [urlArray addObject : [ NSString stringWithFormat : @ "display=%@", @ "mobile" ] ]; for ( int i = 0; i< [urlArray count ]; i ++ ) { if (i == 0 ) { parameter = [ [parameter stringByAppendingString : @ "?" ] stringByAppendingString : [urlArray objectAtIndex :i ] ]; } else { parameter = [ [parameter stringByAppendingString : @ "&" ] stringByAppendingString : [urlArray objectAtIndex :i ] ]; } } NSString * urlString = [URL_Authorize copy ]; urlString = [urlString stringByAppendingString :parameter ]; [urlArray release ]; return urlString; } + ( NSString * )SinaGetToKenURLString { NSString * parameter = @ ""; NSMutableArray * urlArray = [ [ NSMutableArray alloc ] init ]; [urlArray addObject : @ "grant_type=authorization_code" ]; [urlArray addObject : [ NSString stringWithFormat : @ "code=%@", [ [SinaCodePathAndDic code ] objectForKey : @ "code" ] ] ]; [urlArray addObject : [ NSString stringWithFormat : @ "client_id=%@",SinaAppkey ] ]; [urlArray addObject : [ NSString stringWithFormat : @ "redirect_uri=%@",SinaCOMEBACK_URL ] ]; [urlArray addObject : [ NSString stringWithFormat : @ "client_secret=%@",SinaAppSecret ] ]; for ( int i = 0; i< [urlArray count ]; i ++ ) { if (i == 0 ) { parameter = [ [parameter stringByAppendingString : @ "?" ] stringByAppendingString : [urlArray objectAtIndex :i ] ]; } else { parameter = [ [parameter stringByAppendingString : @ "&" ] stringByAppendingString : [urlArray objectAtIndex :i ] ]; } } NSString * urlString = [URL_Access copy ]; urlString = [urlString stringByAppendingString :parameter ]; return urlString; } @end #import <UIKit/UIKit.h> #import "MainViewController.h" @protocol SinaWebViewControllerDeletage <NSObject> - ( void )hasCodeForSina; @end @interface SinaWebViewController : MainViewController<UIWebViewDelegate> { UIWebView * web; NSMutableData * data; id<SinaWebViewControllerDeletage>deletage; } @property (nonatomic,assign ) id<SinaWebViewControllerDeletage>deletage; @end #import "SinaWebViewController.h" #import "SinaUrl.h" #import "SinaCodePathAndDic.h" @implementation SinaWebViewController @synthesize deletage; - ( id )initWithNibName : ( NSString * )nibNameOrNil bundle : ( NSBundle * )nibBundleOrNil { self = [super initWithNibName :nibNameOrNil bundle :nibBundleOrNil ]; if (self ) { // Custom initialization } return self; } - ( void )dealloc { [web release ]; [data release ]; [super dealloc ]; } - ( void )didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning ]; // Release any cached data, images, etc that aren't in use. } #pragma mark - View lifecycle - ( void )popModeVC { [self dismissModalViewControllerAnimated : YES ]; } // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - ( void )viewDidLoad { [super viewDidLoad ]; UINavigationBar * myBar_ = [ [UINavigationBar alloc ] initWithFrame :CGRectMake ( 0, 0, 320, 44 ) ]; [myBar_ setTintColor : [UIColor orangeColor ] ]; UINavigationItem * item_ = [ [UINavigationItem alloc ] initWithTitle :NSLocalizedString ( @ "新浪认证", nil ) ]; UIBarButtonItem * buttonItem_ = [ [UIBarButtonItem alloc ] initWithTitle :NSLocalizedString ( @ "返回", nil ) style :UIBarButtonItemStyleBordered target :self action : @selector (popModeVC ) ]; item_.leftBarButtonItem = buttonItem_; [buttonItem_ release ]; [myBar_ pushNavigationItem :item_ animated : NO ]; [item_ release ]; [self.view addSubview :myBar_ ]; web = [ [UIWebView alloc ] initWithFrame :CGRectMake ( 0, 44, 320, 480 ) ]; [web setDelegate :self ]; NSURL * url = [ NSURL URLWithString : [SinaUrl SinaUrlString ] ]; NSLog ( @ "URL=%@",url ); NSURLRequest * re = [ NSURLRequest requestWithURL :url ]; [web loadRequest :re ]; data = [ [ NSMutableData alloc ] init ]; [self.view addSubview :web ]; } - ( BOOL )webView : (UIWebView * )webView shouldStartLoadWithRequest : ( NSURLRequest * )request navigationType : (UIWebViewNavigationType )navigationType { NSString * urlStr = [ [request URL ] relativeString ]; NSString * str = [ [urlStr componentsSeparatedByString : @ "?" ] objectAtIndex : 0 ]; if ( [str isEqualToString : @ "http://www.m-bao.com/" ] ) { NSString * codeStr = [ [ [ [urlStr componentsSeparatedByString : @ "code=" ] objectAtIndex : 1 ] componentsSeparatedByString : @ "&" ]objectAtIndex : 0 ]; NSMutableDictionary * codeDic = [ NSMutableDictionary dictionary ]; [codeDic setValue :codeStr forKey : @ "code" ]; NSLog ( @ "%@",codeStr ); [codeDic writeToFile : [SinaCodePathAndDic writeToFilePath ] atomically : YES ]; if (deletage ) { [deletage hasCodeForSina ]; } [self dismissModalViewControllerAnimated : YES ]; } else { } return YES; } - ( void )webViewDidStartLoad : (UIWebView * )webView { [self webStartLoad ]; } - ( void )webViewDidFinishLoad : (UIWebView * )webView { [self webFinishLoad ]; } - ( void )viewDidUnload { [super viewDidUnload ]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - ( BOOL )shouldAutorotateToInterfaceOrientation : (UIInterfaceOrientation )interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait ); } @end |