В моем приложении мне нужно добавить токен аутентификации в HTTPHeadField
за каждый вызов API NSURLRequest
, который я делаю на своем сервере. Этот токен действителен только в течение 2 дней. Когда он станет недействительным, я получаю ответ «token_invalid» с моего сервера, что означает, что мне нужно отправить вызов API на мой сервер, чтобы обновить токен аутентификации.iOS - Обновление истекшего токена аутентификации в NSURLSession
Проблема, с которой сложно обернуть голову, заключается в том, что эти NSURLRequests
выполняются одновременно, поэтому, когда каждый из них выходит из строя из-за истекшего токена, ВСЕ из них попытаются обновить токен. Как настроить это так, чтобы токен обновлялся ONCE, и когда это было сделано, повторите попытку всех неудавшихся запросов?
ПРОГРЕСС
То, что я до сих пор работает, но только до определенной степени, что сбивает с толку меня. Когда я успешно обновляю токен аутентификации, я повторяю все неудавшиеся запросы и повторно их пытаюсь. Тем не менее, все они повторно пытались в вызове ONE API, который отвечал за обновление токена аутентификации.
Например, производится 3 вызова API (запросы друзей, уведомления и получение друзей пользователя). Если вызов API «Get Friend Requests» завершается с ошибкой в первую очередь, он отвечает за обновление токена. Два других запроса API помещаются в массив failedRequests
. Когда токен аутентификации успешно обновляется, только блок успеха «Получить запрос друга» передается через ... 3 раза!
Я понимаю, почему это происходит, потому что я повторно пытаюсь выполнить все неудавшиеся запросы API в контексте одного метода NSURLRequest
sendTask
. Есть ли способ перепробовать неудавшиеся запросы в их контексте, когда токен аутентификации обновляется таким образом, который работает 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];
}
Вы когда-нибудь находили хорошее решение? Я имею дело с подобной проблемой. Я проверяю ответ API, и если он не работает из-за истекшего токена, я обновляю его, а затем повторно вызываю ту же функцию, которая выполняет URLSession, но мой токен обновляется дважды, и я даже не знаю, почему ... Я играю с сохранением срока действия токена где-то где-то, и просто проверить это сначала, и если его истекшее обновление до отправки первоначального запроса. – snoop168