我有一个授权功能,如果它发出未经授权的请求,它将在我的应用程序中运行。我最初在POC中构建了auth功能,现在我已将其转移到我正在处理的应用程序中。我注意到一个有趣的问题,如果我在启动时将令牌设置为无效(这只在启动时发生),那么从应用程序发出大约4个身份验证请求。据我所知,auth的响应在请求发出后返回,因此在应用程序意识到它具有有效令牌之前会有一些堆叠。如果使用应用程序时身份验证令牌过期,该功能将完美运行,此问题纯粹是在加载时。
我已经决定解决这个问题的方法是使auth函数独占。我做了一些研究,允许一次调用函数并遇到@synchronized。这很有道理,但我不太清楚如何将它实现到我的功能中。我的auth功能如下所示:
+ (void)requestAuthTokenWithBlock:(void (^)(void))completion {
NSLog(@"requestNewToken - Called: Requesting a new authorization bearer token.");
[[NSURLCache sharedURLCache] removeAllCachedResponses];
//Build request URL String
NSString *requestString = [NSString stringWithFormat:@"%@%@",baseURL,authRequestURL];
//Encode password so that it can be safely sent in request
NSString *encodedPassword = [kU1Password stringByAddingPercentEncodingForRFC3986];
//Populate post request with user credentials
NSString *post = [NSString stringWithFormat:@"client_id=%@&password=%@&grant_type=%@", kU1ClientId, encodedPassword, kU1GrantType];
//Encode post string & convert to type NSData
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
//Calculate the length of the post string
NSString *postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]];
//Initialize url request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
//Set the url for which you will pass your request data
[request setURL:[NSURL URLWithString:requestString]];
//Set HTTP method for request
[request setHTTPMethod:@"POST"];
//Set HTTP header field with length of post data
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
//Set the encoded value for HTTP Header field
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
//Set the HTTP body of the urlrequest with our post data
[request setHTTPBody:postData];
//Create full request
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"Status Code: %ld\n - requestAuthTokenWithBlock - ",(long)httpResponse.statusCode);
NSString *message = [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode];
NSLog(@"Message: %@", message);
//Check for an error, if there is no error we proceed.
if (!error) {
NSLog(@"requestAuthToken - Successful responce from server");
//Populate the auth object with the parse json data (handled entirely in the builder)
AuthToken *auth = [TokenBuilder authFromJSON:data error:&error];
//Save the auth & refresh tokens in the keychain
[SAMKeychain setPassword:auth.AuthToken forService:kServer account:kKeyAccessToken];
[SAMKeychain setPassword:auth.RefreshToken forService:kServer account:kKeyRefreshToken];
//Trigger completion block
if (completion)
{
completion();
}
}
else {
//Failed request
//Trigger completion block
if (completion)
{
completion();
}
}
}];
[dataTask resume];
}
如果应用程序有一个令牌,它只能从这个switch语句调用:
switch (httpResponse.statusCode) {
case 200 ... 299:{
NSLog(@"SUCCESS");
NSLog(@"Performing any completion related functions!");
retryAttempts = 0;
completion(true, message, data, nil);
return;
}
case 401:{
if (retryAttempts == 0){
NSLog(@"401 Challenge - Retrying Authentication, First Attempt:");
}
else {
NSLog(@"401 Challenge - Retrying Authentication, Attempt %ld", (long)retryAttempts);
}
[self requestAuthTokenWithBlock:^(void){
NSLog(@"requestAuthTokenWithBlock - Completion block called");
[self dataTaskwithRequest:request method:method completion:completion];
}];
retryAttempts += 1;
break;
}
}
我复制了@Synchronized
代码段,但实际上并不知道该把它放在哪里:
@synchronized (<#token#>) {
<#statements#>
}
我尝试将它放入我调用数据任务的令牌方法中:
@synchronized (dataTask) {
[dataTask resume];
}
并且该函数仍被多次调用。我不知道如何解决这个问题,我可以在应用程序的任何地方添加对此函数的调用,并且不认为我可以自己控制请求。我认为保护函数免受多次调用的唯一地方就是函数本身。作为旁注,我添加了一个布尔值,该函数在函数启动时设置为false,在函数结束时设置为true。
if (canAttempt == NO) {
return;
}
canAttempt = NO;
现在,曾经被调用4次的函数现在返回失败,因为它们未被授权。关于如何在继续之前让应用程序等待此功能的任何想法?