2016-01-31 3 views
1

В моем приложении мне нужно добавить токен аутентификации в HTTPHeadField за каждый вызов API NSURLRequest, который я делаю на своем сервере. Этот токен действителен только в течение 2 дней. Когда он станет недействительным, я получаю ответ «token_invalid» с моего сервера, что означает, что мне нужно отправить вызов API на мой сервер, чтобы обновить токен аутентификации.iOS - Обновление истекшего токена аутентификации в NSURLSession

Проблема, с которой сложно обернуть голову, заключается в том, что эти NSURLRequests выполняются одновременно, поэтому, когда каждый из них выходит из строя из-за истекшего токена, ВСЕ из них попытаются обновить токен. Как настроить это так, чтобы токен обновлялся ONCE, и когда это было сделано, повторите попытку всех неудавшихся запросов?

ПРОГРЕСС

То, что я до сих пор работает, но только до определенной степени, что сбивает с толку меня. Когда я успешно обновляю токен аутентификации, я повторяю все неудавшиеся запросы и повторно их пытаюсь. Тем не менее, все они повторно пытались в вызове ONE API, который отвечал за обновление токена аутентификации.

Например, производится 3 вызова API (запросы друзей, уведомления и получение друзей пользователя). Если вызов API «Get Friend Requests» завершается с ошибкой в ​​первую очередь, он отвечает за обновление токена. Два других запроса API помещаются в массив failedRequests. Когда токен аутентификации успешно обновляется, только блок успеха «Получить запрос друга» передается через ... 3 раза!

Я понимаю, почему это происходит, потому что я повторно пытаюсь выполнить все неудавшиеся запросы API в контексте одного метода NSURLRequestsendTask. Есть ли способ перепробовать неудавшиеся запросы в их контексте, когда токен аутентификации обновляется таким образом, который работает Key-Value Observing?

-(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback 
{ 
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    { 
     MyAPIInterface *__weak weakSelf = self; 
     [self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error) 
     { 
      NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; 
      if (httpResp.statusCode == 401) { 
       if ([error isEqualToString:@"invalid_credentials"]) { 
        errorCallback(@"Invalid username and/or password"); 
       } 
       else if ([error isEqualToString:@"token_expired"]) { 
        // check if request's auth token differs from api's current auth token 
        NSArray *requestHeaderValueComponents = [[request valueForHTTPHeaderField:@"Authorization"] componentsSeparatedByString:@" "]; 
        NSString *requestAuthToken = requestHeaderValueComponents[1]; 

        // if new auth token hasn't been retrieved yet 
        if ([requestAuthToken isEqualToString:weakSelf.authToken]) { 
         NSLog(@"THE AUTH TOKENS ARE EQUAL"); 
         if (!weakSelf.currentlyRefreshingToken.boolValue) { 

          //lock alreadyRefreshingToken boolean 
          weakSelf.currentlyRefreshingToken = [NSNumber numberWithBool:YES]; 
          NSLog(@"NOT REFRESHING TOKEN"); 

          // add mutable failed request (to change auth token header later) to failedRequests array 
          NSMutableArray *mutableFailedRequests = [weakSelf.failedRequests mutableCopy]; 
          NSMutableURLRequest *mutableFailedRequest = [request mutableCopy]; 
          [mutableFailedRequests addObject:mutableFailedRequest]; 
          weakSelf.failedRequests = [mutableFailedRequests copy]; 

          // refresh auth token 
          [weakSelf refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) { 

           //store authToken 
           weakSelf.authToken = response[@"token"]; 
           NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 
           [defaults setObject:weakSelf.authToken forKey:@"authToken"]; 
           [defaults synchronize]; 

           //change auth token http header of each failed request and re-attempt them 
           for (NSMutableURLRequest *failedRequest in weakSelf.failedRequests) { 
            NSString *newAuthHeaderValue = [NSString stringWithFormat:@"Bearer %@", weakSelf.authToken]; 
            [failedRequest setValue:newAuthHeaderValue forHTTPHeaderField:@"Authorization"]; 
            [weakSelf sendTask:failedRequest successCallback:success errorCallback:errorCallback]; 
           } 

           //clear failedRequests array and unlock alreadyRefreshingToken boolean 
           [weakSelf clearFailedRequests]; 
           weakSelf.currentlyRefreshingToken = [NSNumber numberWithBool:NO]; 

           NSLog(@"TOKEN REFRESHING SUCCESSFUL"); 

          } errorCallback:^(NSString *error) { 

           NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY"); 

           //clear failedRequests array 
           [weakSelf clearFailedRequests]; 

           weakSelf.currentlyRefreshingToken = [NSNumber numberWithBool:NO]; 

           errorCallback(@"Your login session has expired"); 

          }]; 
         } 
         else { 
          NSLog(@"ALREADY REFRESHING TOKEN. JUST ADD TO FAILED LIST"); 
          // add mutable failed request (to change auth token header later) to failedRequests array 
          NSMutableArray *mutableFailedRequests = [weakSelf.failedRequests mutableCopy]; 
          NSMutableURLRequest *mutableFailedRequest = [request mutableCopy]; 
          [mutableFailedRequests addObject:mutableFailedRequest]; 
          weakSelf.failedRequests = [mutableFailedRequests copy]; 
         } 
        } 
        // if new auth token has been retrieved, simply re-attempt request with new auth token 
        else { 
         NSMutableURLRequest *failedRequest = [request mutableCopy]; 
         NSString *newAuthHeaderValue = [NSString stringWithFormat:@"Bearer %@", weakSelf.authToken]; 
         [failedRequest setValue:newAuthHeaderValue forHTTPHeaderField:@"Authorization"]; 
         [weakSelf sendTask:failedRequest successCallback:success errorCallback:errorCallback]; 
        } 
       } 
       else { 
        errorCallback(error); 
       } 
      } 
      else { 
       errorCallback(error); 
      } 
     }]; 
    }]; 
    [task resume]; 
} 
+0

Вы когда-нибудь находили хорошее решение? Я имею дело с подобной проблемой. Я проверяю ответ API, и если он не работает из-за истекшего токена, я обновляю его, а затем повторно вызываю ту же функцию, которая выполняет URLSession, но мой токен обновляется дважды, и я даже не знаю, почему ... Я играю с сохранением срока действия токена где-то где-то, и просто проверить это сначала, и если его истекшее обновление до отправки первоначального запроса. – snoop168

ответ

0

1) Я думаю, вы должны получить токен от успешного входа в учетную запись.

2) Поэтому, когда срок действия токена истек. Показать экран входа пользователю.

3) Если пользователь успешно зарегистрирован, он получает новый токен доступа.

4) Вы можете использовать это для следующего запроса

+0

У меня уже есть пользователь, получающий токен от успешного входа в учетную запись. Поток прецедентов выглядит следующим образом: токен действителен в течение 2 дней. После этого он обновляется, но если пользователь не обновляет его в течение 2 недель (просто используя приложение), то токен больше не обновляется, и пользователю будет показано сообщение 'UIAlertController':« В вашей сессии входа есть expired "и будет возвращен на экран входа в систему. – Rafi

+0

Я отредактировал свой вопрос с моим прогрессом и последним препятствием, с которым я сталкиваюсь, чтобы это работало. Пожалуйста, проверьте это. – Rafi