2013-04-10 15 views
8

Przez cały dzień łamałem sobie głowę.Implementacja OAuth 1.0 w aplikacji na iOS

Chciałbym zintegrować moją aplikację na iOS z aplikacją Withings. Używa OAuth 1.0 i nie mogę w pełni zrozumieć, jak go wdrożyć.

Pobierałem wiele framworks OAuth (MPOAuth, gtm-oauth, ssoauthkit), ale nie mogłem dowiedzieć się, co dokładnie powinienem zrobić.

Dużo przeszukałem, także w przepełnieniu stosu, aby uzyskać dobre referencje, jak wdrożyć OAuth 1.0 ogólnie & integrując z Withings w szczególności bez powodzenia.

Prosimy o wyjaśnienie procesu integracji aplikacji na iOS z interfejsem API wymagającym OAuth 1.0. Przykłady kodu byłyby bardzo pomocne. Sugerowane frameworki innych firm również byłyby miłe.

Aby wyjaśnić, w pełni rozumiem zasady OAuth 1.0, mam problemy z jego implementacją w mojej aplikacji.

Myślę, że dokładna odpowiedź z przykładami kodu i dobrymi referencjami byłaby bardzo pomocna dla wielu osób, ponieważ nie mogłem jej znaleźć. Jeśli ktoś ma dobre doświadczenia z jego wdrażaniem, poświęć trochę czasu, aby go udostępnić.

+0

Pan spojrzał na [projekt przykład zawarte w GTM-OAuth] (https://github.com/jdg/gtm-oauth/tree/master/Examples/OAuthSample)? – bdesham

+0

tak, mam. Te przykłady projektów są naprawdę trudne do przejścia i pełnego zrozumienia. –

+0

Jest tam dużo złego kodu OAuth, szczególnie w systemie iOS. Więc uważaj. Jedynym przyzwoitym, jaki kiedykolwiek spotkałem, był Google (gtm-oauth), więc otrzymałem +1 ode mnie. –

Odpowiedz

11

TDOAuth moim zdaniem było najlepszym rozwiązaniem. to jest czyste i proste, tylko jeden plik .h i .m pracować, i żadnych skomplikowanych przykładowe projekty ..

To OAuth 1.0 Przepływ:

krok 1 - get żądanie tokenów

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

krok 2 - get autoryzacji tokenu (ładując żądanie w UIWebView, metoda webViewDidFinishLoad delegat będzie obsługiwać połączenie z powrotem ..)

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

obsłużyć Webview jak postępować, aby zainicjować krok 3 (Znam isAuthorizeCallBack pachnie dużo, ale spełnia swoje zadanie, należy ją byłaby ..)

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

i wreszcie - krok 3 - uzyskać dostęp symboliczny

- (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

Zaimplementowałem twój kod, ale utknęło mi w kroku 3. Wyświetlam stronę logowania Withings w widoku strony internetowej, ale zawsze zwraca ona "Nieprawidłowy token przysięgi". Czy czegoś brakuje? Z góry dziękuję. – Dmorneault

+0

@Dmorneault, Edytowałem odpowiedź z małą poprawką. spójrz na metodę webViewDidFinishLoad i dodaj kod pod znakiem "brzydka łatka, aby naprawić nieprawidłowy błąd tokena". zauważ, że wywołuje metodę o nazwie "startOAuthFlow", która jest po prostu krokiem 1 i krokiem 2 ponownie. Wydaje się, że problem buforowania i próbowałem go rozwiązać przy wsparciu Withings, ale skończyło się mieszka ten brzydki ale roboczy poprawkę .. –

+0

skąd tworzyć wnioski o interakcji z API po uwierzytelnieniu? –

0

Proponuję sprawdzić ten projekt zarówno jako odniesienie, jak i naprawdę działającą klasę OAuth. Dziedziczy po innym wspaniałym projekcie, więc będziesz musiał dodać oba w swoim. Sprawdź, czy licencja będzie pasować do twoich wymagań. https://github.com/rsieiro/RSOAuthEngine

+0

Jeśli projekt jest nieaktualny, nie ma sensu go przypisywać. W momencie odpowiedzi zadziałało idealnie i użyłem go w mojej aplikacji z powodzeniem. – Andrea

2

ja dodatkowo zaoszczędzić nagłówki żądania tutaj

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; 

W metodzie wywołania zwrotnego dodaję brakujące parametry do żądania. Robiąc to w ten sposób, unikam "brzydkiej poprawki łatki".

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

Mam nadzieję, że to pomoże ktoś

Powiązane problemy