NSURLSession With Basic Authentication Challenge

2020-08-01 08:26发布

问题:

I searched all the solution avaliable in stackoverflow. Still confused with this.
Please point me if i am doing any mistake. I am getting 401 error.

NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL        URLWithString:@"http://qa.api.xxxxxx.com/v0/jobs/93033"]];
NSString *authStr = @"xxxxxxxx:xxxxxxxxxxx";
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@",[authData base64EncodedStringWithOptions:0]];
[request setValue:authValue forHTTPHeaderField:@"Authorization"];
request.HTTPMethod = @"GET";
[request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
//create the task
NSURLSessionDataTask* task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    if (httpResponse.statusCode == 200)
    {
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@",json);
        dispatch_async(dispatch_get_main_queue(), ^{
        });
    } else {
        // failure: do something else on failure
        NSLog(@"httpResponse code: %@", [NSString stringWithFormat:@"%ld", (unsigned long)httpResponse.statusCode]);
        NSLog(@"httpResponse head: %@", httpResponse.allHeaderFields);
        return;
    }

}];

[task resume];

回答1:

Perhaps your request is redirected to some where else with a new request which is auto-generated by NSURLSession without authorization header.

You could use Wireshark to track your request exactly happened.

If your request is redirected, you can use the following methods to make sure the new request is sending with authentication information:

1. Use Delegate Method to Handle Authentication

- (void)URLSession:(NSURLSession *)session 
              task:(NSURLSessionTask *)task 
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
    if (challenge.previousFailureCount > 1) {
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
    }else {
        NSURLCredential *credential = [NSURLCredential credentialWithUser:@"user"
                                                                 password:@"pswd"
                                                              persistence:NSURLCredentialPersistenceForSession];
        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
    }
}

Should be best way to handle authentications.

2. Use Delegate Method to Add Authentication Header to New Request

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest *))completionHandler {
    NSMutableURLRequest *newRequest = request.mutableCopy;
    // Add authentication header here.
    completionHandler(newRequest);
}

Add authentication header again when your request gets redirect.

3. Set Authentication Header As Additional Header To NSURLSession

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPAdditionalHeaders = @{@"Authorization":@"Basic xxxxxxxxxxxxxxxxxx"};
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

Make sure NSURLSession creates new request with that authentication header.



回答2:

Perhaps your output of authValue contains new lines after you do base64, try to log the string and remove new lines, otherwise the header won't set.



回答3:

Using didReceiveAuthenticationChallenge approach, is the correct way to work with basic authorization in iOS.

Request:

 NSURL *URL = [NSURL URLWithString:@"http://qa.api.freshersworld.com/v0/jobs/93033"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL
                                             cachePolicy:NSURLRequestUseProtocolCachePolicy
                                         timeoutInterval:30.0];

 NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
 [connection start];

Delegate:

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
      if ([challenge previousFailureCount] == 0) {
        NSLog(@"received and handle authentication challenge");
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:@"xxxx"
                                                                    password:@"xxxx"
                                                                 persistence:NSURLCredentialPersistenceForSession];
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
    }
    else {
        NSLog(@"previous authentication failure");
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
      NSLog(@"%@", response);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
      NSString* responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
      NSLog(@"%@", responseString);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
}

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