在iOS应用中实施OAuth 1.0

时间:2013-04-10 15:51:33

标签: ios objective-c api oauth

我整天都在为此而烦恼。

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

我一直在下载多个OAuth framworks(MPOAuthgtm-oauthssoauthkit),但无法完全弄清楚我应该做些什么。

我搜索了很多,也是在堆栈溢出中,以获得有关如何实施OAuth 1.0的一般参考资料。特别是与Withings融合没有成功。

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

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

我认为通过代码示例和良好参考的完整答案对很多人来说非常有帮助,因为我找不到。如果有人有很好的实施经验,请花点时间分享。

3 个答案:

答案 0 :(得分:12)

我认为

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];

按照以下方式处理webView以启动第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"]];
}

答案 1 :(得分:3)

我另外在这里保存请求标题

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;
}

我希望它会帮助某人

答案 2 :(得分:0)

我建议您将此项目作为参考和真正有效的OAuth类进行检查。它继承了另一个伟大的项目,因此您需要在您的项目中添加两者。检查许可证是否符合您的要求。 https://github.com/rsieiro/RSOAuthEngine