2014-02-07 98 views
1

我正在使用Google的GTMOAuth for iOS/Mac SDK以便能夠連接API,如API API和Instagram API。它一切正常,但是當用戶進行身份驗證時,我只能獲取訪問令牌。這一切都很好,但過了一段時間,訪問令牌失效,用戶不得不重新登錄,這很糟糕。GTM OAuth不下載刷新令牌 - iOS

我的問題是,當用戶進行身份驗證,我只得到回一個訪問令牌,並沒有別的...

感謝你的幫助:)

回答

3

可能是這樣一個對您有幫助.. !

我正在使用Google oauth 2.0進行谷歌驅動器身份驗證。

在Google完成身份驗證方法中,像這樣在NSUSerDefaults中保存accesstoken和刷新標記值。

- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)authResult 

      error:(NSError *)error 
    { 

     if (error != nil) 
     { 

      [self showAlert:@"Authentication Error" message:error.localizedDescription]; 

      self.driveService.authorizer = nil; 

     } 
     else 
     { 
      self.driveService.authorizer = authResult; 

      self.auth = authResult; 

      NSLog(@"\n accessToken value is %@",self.auth.accessToken); 

      [[NSUserDefaults standardUserDefaults] setValue:self.auth.refreshToken forKey:@"refreshToken"]; 

      [[NSUserDefaults standardUserDefaults] setValue:self.auth.accessToken forKey:@"accessToken"]; 

      [[NSUserDefaults standardUserDefaults] synchronize]; 


     } 

    } 

之後當過您要使用的存取權限令牌用於執行API調用首先要使用從現有NSUserDefaults的價值的accessToken一個電話,之後,在URL響應檢查狀態代碼。如果您獲得狀態碼「401」,則表示您的訪問令牌已過期,無效。然後,你必須使用NSUserDefaults中保存的刷新標記值來請求刷新標記。

這是您第一次檢查accesstoken有效與否的API調用。

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response 
    { 
     NSLog(@"Did Receive Response %@", response); 
     NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; 
     //int responseStatusCode = [httpResponse statusCode]; 
     if (httpResponse.statusCode == 200) { 
//Your api call success and accesstoken is valid. 


     } else if(httpResponse.statusCode == 401 && connection == self.conn2) { 

      [[self appDelegate] refreshAccessToken]; 
     } 
    } 

這是用於從刷新令牌中請求新的accesstoken。

-(void)refreshAccessToken { 


    NSString *requestString = [NSString stringWithFormat:@"https://accounts.google.com/o/oauth2/token"]; 
     NSString *string = [NSString stringWithFormat:@"client_id=%@&client_secret=%@&refresh_token=%@&grant_type=refresh_token",kClientID,kClientSecret,[[NSUserDefaults standardUserDefaults] valueForKey:@"refreshToken"]]; 
    NSData *postData = [string dataUsingEncoding:NSUTF8StringEncoding]; 
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestString]]; 
    NSLog(@"\n request str : %@",request); 

    NSLog(@"\n refresh token value is %@",[[NSUserDefaults standardUserDefaults] valueForKey:@"refreshToken"]); 
    [request setHTTPMethod:@"POST"]; 
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 
    [request setHTTPBody:postData]; 
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];//connectionWithRequest:request delegate:self]; 
    if(connection) 
    { 
     NSLog(@"Connection Successful"); 
    } 
    else 
    { 
     NSLog(@"Connection could not be made"); 
    } 

    [connection start]; 


} 

作爲響應再次檢查狀態碼,如果狀態碼是200.然後更新userdafaults中的值。

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    NSLog(@"Did Receive Response %@", response); 
    //NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; 
    self.data = [NSMutableData data]; 
} 

- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data 
{ 
    NSLog(@"Did Receive Data %@", data); 
    [self.data appendData:data]; 
} 

- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error 
{ 
    NSLog(@"Did Fail %@",error); 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    NSLog(@"Did Finish"); 
    // Do something with responseData 
    NSError *err; 
    id JSon = [NSJSONSerialization JSONObjectWithData:self.data options:kNilOptions error:&err]; 
    if (err) { 
     NSLog(@"%@",err); 
    } 
    else { 
     NSLog(@"Json %@",JSon); 
     [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"accessToken"]; 
     [[NSUserDefaults standardUserDefaults] setObject:[JSon valueForKey:@"access_token"] forKey:@"accessToken"]; 
     [[NSUserDefaults standardUserDefaults] synchronize]; 

    } 
} 

這是我對堆棧溢出的第一個答案。對不起,有任何錯誤。

更新下 - 寫的Supertecnoboff

而且記住這一點。對於Google等一些API,如果您希望它爲您提供刷新令牌,則需要添加「approval_prompt = force」和「access_type = offline」。爲了添加這些參數,你必須編輯GTMOAuth2SignIn.m文件並替換「paramsDict」這個的NSMutableDictionary:

NSMutableDictionary *paramsDict = [NSMutableDictionary dictionaryWithObjectsAndKeys: 
           @"code", @"response_type", 
           clientID, @"client_id", 
           scope, @"scope", // scope may be nil 
           @"force", @"approval_prompt", 
           @"offline", @"access_type", 
           nil]; 
+0

非常感謝你的回答。它在理解邏輯方面真的幫了我很大的忙。但是我仍然有一個問題。做「self.auth.refreshToken」返回null ....當我試圖下載訪問令牌「self.auth.accessToken」時,它的工作原理。那麼,爲什麼它不下載任何刷新標誌? – Supertecnoboff

+0

我沒有給你。可以請給我解釋一下,所以也許我可以幫助你。 –

+0

所以基本上你知道名爲「finishedWithAuth」的方法,你可以通過執行以下操作獲得accessToken和refreshToken的副本:「self.auth.accessToken」和「self.auth.refreshToken」。那麼基本上,當我做「self.auth.accessToken」我可以得到一個accessToken的副本。但是,當我嘗試做「NSString * refresh = self.auth.refreshToken」我無法獲取刷新標記,因爲刷新標記爲空..... ????? – Supertecnoboff

2

您還可以使用GTMOAuth2AuthenticationauthorizeRequest:completionHandler:方法

如果您的應用程序保存授權的鑰匙串(通過設置控制器的keychainItemName),它可以在下次進行檢索應用程序啓動:

GTMOAuth2Authentication *auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName 
                          clientID:kClientID 
                        clientSecret:kClientSecret]; 

NSLog(@"accessToken: %@", auth.accessToken); //If the token is expired, this will be nil 

和那麼你可以這樣刷新訪問令牌:

// authorizeRequest will refresh the token, even though the NSURLRequest passed is nil 
[auth authorizeRequest:nil 
      completionHandler:^(NSError *error) { 
       if (error) { 
        NSLog(@"error: %@", error); 
       } 
       else { 
        NSLog(@"accessToken: %@", auth.accessToken); //it shouldn´t be nil 
       } 
      }]; 

令牌將被刷新,你可以繼續查詢。

+0

感謝您的回答。我還有一個問題:是否需要在Google開發人員控制檯中爲WEB Key創建憑據以獲取client_secret,或者我可以在iOS app/.plist文件中找到它? – ArtStyle

+1

據我所知,我認爲你需要在Google開發者控制檯中創建一些憑據。不確定Web密鑰或iOS客戶端密鑰。 除了您需要在app/.plist中存儲一些參數(如ClientID和/或ClientSecret)以使Google的圖書館工作。 – jdev

+0

在證書中,我只有iOS的clientID,所以請求中的client_secret可能爲零? – ArtStyle