2013-04-10 58 views
8

我一整天都在为这件事烦恼。在iOS应用中实现OAuth 1.0

我希望将我的iOS应用程序与Withings api集成。它使用OAuth 1.0,我似乎无法完全理解如何实现它。

我一直在下载多个OAuth framworks(MPOAuth,gtm-oauth,ssoauthkit),但不能完全弄清楚我应该做什么。

我搜索了很多,也在堆栈溢出,以便如何实现OAuth 1.0的一般&与Withings尤其没有成功的集成。

请解释将iOS应用程序与需要OAuth 1.0的api集成的流程。代码示例会非常有帮助。建议的第三方框架也不错。

为了澄清,我完全理解了OAuth 1.0原则,我只是在我的应用程序中实际执行它时遇到问题。

我认为,通过代码示例和良好参考的详尽解答对于很多人来说都是非常有用的,因为我无法找到它。如果任何人有很好的实施经验,请花时间分享。

+0

你看[在GTM-的OAuth包括示例项目(https://github.com/jdg/gtm-oauth/tree/master/Examples/OAuthSample)? – bdesham 2013-04-10 16:00:32

+0

是的,我有。这些示例项目真的很难浏览并完全理解它们。 – 2013-04-10 16:11:47

+0

这里有很多不好的OAuth代码,尤其是iOS。所以要小心。我遇到过的唯一体面的就是Google的(gtm-oauth),因此我可以收到+1。 – 2013-04-10 17:43:55

回答

11

TDOAuth在我看来是最好的解决方案。它是干净和简单,只有一个h和.m文件的工作,并没有复杂的示例项目..

这是OAuth的1.0流量:

第1步 - 获取请求令牌

//withings additional params 
NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 
[dict setObject:CALL_BACK_URL forKey:@"oauth_callback"]; 

//init request 
NSURLRequest *rq = [TDOAuth URLRequestForPath:@"/request_token" GETParameters:dict scheme:@"https" host:@"oauth.withings.com/account" consumerKey:WITHINGS_OAUTH_KEY consumerSecret:WITHINGS_OAUTH_SECRET accessToken:nil tokenSecret:nil]; 

//fire request 
NSURLResponse* response; 
NSError* error = nil; 
NSData* result = [NSURLConnection sendSynchronousRequest:rq returningResponse:&response error:&error]; 
NSString *s = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]; 
//parse result 
NSMutableDictionary *params = [NSMutableDictionary dictionary]; 
NSArray *split = [s componentsSeparatedByString:@"&"]; 
for (NSString *str in split){ 
    NSArray *split2 = [str componentsSeparatedByString:@"="]; 
    [params setObject:split2[1] forKey:split2[0]]; 
} 

token = params[@"oauth_token"]; 
tokenSecret = params[@"oauth_token_secret"]; 

步骤2 - 获取授权令牌(通过加载在一个UIWebView的请求,webViewDidFinishLoad委托方法将处理呼叫背面..)

//withings additional params 
NSMutableDictionary *dict2 = [NSMutableDictionary dictionary]; 
[dict setObject:CALL_BACK_URL forKey:@"oauth_callback"]; 

//init request 
NSURLRequest *rq2 = [TDOAuth URLRequestForPath:@"/authorize" GETParameters:dict2 scheme:@"https" host:@"oauth.withings.com/account" consumerKey:WITHINGS_OAUTH_KEY consumerSecret:WITHINGS_OAUTH_SECRET accessToken:token tokenSecret:tokenSecret]; 

webView.delegate = self; 
[DBLoaderHUD showDBLoaderInView:webView]; 
[webView loadRequest:rq2]; 

处理web视图如下发起第3步(我知道isAuthorizeCallBack闻起来有很多,但它的工作,应该重构它..)

- (void)webViewDidFinishLoad:(UIWebView *)aWebView 
{ 
    [DBLoaderHUD hideDBLoaderInView:webView]; 

    NSString *userId = [self isAuthorizeCallBack]; 
    if (userId) { 

     //step 3 - get access token 
     [DBLoaderHUD showDBLoaderInView:self.view]; 
     [self getAccessTokenForUserId:userId]; 
    } 

    //ugly patchup to fix an invalid token bug 
    if ([webView.request.URL.absoluteString isEqualToString:@"http://oauth.withings.com/account/authorize?"]) 
    [self startOAuthFlow]; 
} 

- (NSString *)isAuthorizeCallBack 
{ 
    NSString *fullUrlString = webView.request.URL.absoluteString; 

    if (!fullUrlString) 
     return nil; 

    NSArray *arr = [fullUrlString componentsSeparatedByString:@"?"]; 
    if (!arr || arr.count!=2) 
     return nil; 

    if (![arr[0] isEqualToString:CALL_BACK_URL]) 
     return nil; 

    NSString *resultString = arr[1]; 
    NSArray *arr2 = [resultString componentsSeparatedByString:@"&"]; 
    if (!arr2 || arr2.count!=3) 
     return nil; 

    NSString *userCred = arr2[0]; 
    NSArray *arr3 = [userCred componentsSeparatedByString:@"="]; 
    if (!arr3 || arr3.count!=2) 
     return nil; 

    if (![arr3[0] isEqualToString:@"userid"]) 
     return nil; 

    return arr3[1]; 
} 

- (void)startOAuthFlow 
{ 
    [self step1]; 
    [self step2]; 
} 

,最后 - 第3步 - 获得访问令牌

- (void)getAccessTokenForUserId:(NSString *)userId 
{ 
    //step 3 - get access token 

    //withings additional params 
    NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 
    [dict setObject:CALL_BACK_URL forKey:@"oauth_callback"]; 
    [dict setObject:userId forKey:@"userid"]; 

    //init request 
    NSURLRequest *rq = [TDOAuth URLRequestForPath:@"/access_token" GETParameters:dict scheme:@"https" host:@"oauth.withings.com/account" consumerKey:WITHINGS_OAUTH_KEY consumerSecret:WITHINGS_OAUTH_SECRET accessToken:token tokenSecret:tokenSecret]; 

    //fire request 
    NSURLResponse* response; 
    NSError* error = nil; 
    NSData* result = [NSURLConnection sendSynchronousRequest:rq returningResponse:&response error:&error]; 
    NSString *s = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]; 

    //parse result 
    NSMutableDictionary *params = [NSMutableDictionary dictionary]; 
    NSArray *split = [s componentsSeparatedByString:@"&"]; 
    for (NSString *str in split){ 
     NSArray *split2 = [str componentsSeparatedByString:@"="]; 
     [params setObject:split2[1] forKey:split2[0]]; 
    } 

    [self finishedAthourizationProcessWithUserId:userId AccessToken:params[@"oauth_token"] AccessTokenSecret:params[@"oauth_token_secret"]]; 
} 
+0

我已经实现了你的代码,但是我陷入了第3步。我在webview中显示Withings登录页面,但它总是返回“Invalid oath token”。我错过了什么吗?提前致谢。 – Dmorneault 2013-07-14 18:51:25

+0

@Dmorneault,我用一个小小的修正编辑了答案。查看webViewDidFinishLoad方法并在标记“丑陋补丁修复无效令牌错误”下添加代码。注意它调用了一个名为“startOAuthFlow”的方法,它只是step1和step2。似乎有一个缓存问题,我试着用Withings支持解决它,但我最终生活在这个丑陋但工作的补丁.. – 2013-07-15 10:44:44

+0

你是如何创建身份验证后与API交互的请求? – 2013-12-14 18:49:16

0

我建议你检查这个项目既作为参考,也作为一个真正的工作OAuth类。它继承了另一个伟大的项目,因此您需要在您的项目中添加这两个项目。检查许可证是否适合您的要求。 https://github.com/rsieiro/RSOAuthEngine

+0

如果该项目已过时,则无法使用downvote。在答案的时候,它的功能完全适用于我的一个应用程序,并取得了成功。 – Andrea 2015-07-18 10:58:03

2

我additionaly这里保存请求头

NSMutableDictionary *dict2 = [NSMutableDictionary dictionary]; 
[dict2 setObject:CALL_BACK_URL forKey:@"oauth_callback"]; 
NSURLRequest *rq2 = [TDOAuth URLRequestForPath:@"/authorize" 
           GETParameters:dict2 
             scheme:@"https" 
              host:@"oauth.withings.com/account" 
            consumerKey:WITHINGS_OAUTH_KEY 
           consumerSecret:WITHINGS_OAUTH_SECRET 
            accessToken:self.token 
            tokenSecret:self.tokenSecret]; 
headers = rq2.allHTTPHeaderFields; 

而在回调方法中,我会将缺少的参数添加到请求中。通过这样做,我避免了“丑陋的补丁修复”。

- (BOOL)webView:(UIWebView *)wV shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ 
if (![request.allHTTPHeaderFields objectForKey:@"Authorization"] && 
    [request.URL.absoluteString rangeOfString:@"acceptDelegation=true"].location == NSNotFound){ 
    NSMutableURLRequest *mutableCp = [request mutableCopy]; 
    NSLog(@"request :::%@", request); 
    [mutableCp setAllHTTPHeaderFields:headers]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [webView loadRequest:mutableCp]; 
    }); 
    return NO; 
} 
return YES; 
} 

我希望这会帮助别人