Generally I like to just "fire and forget" with NSURL's sendAsynchronousRequest class method using the completion handler block but it seems that might not be an option when authentication is needed.
When using a completion handler style request like this:
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.mysite.com/"]]
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
//Do Stuff
}];
What is the proper way to handle authentication? Do I need to alloc and init the NSURLConnection and set a delegate instead of doing using this class method style? I think I understand how to authenticate correctly with the delegate function but I'm trying to figure out if I can include that in the completionHandler block or if there is a better way to do this.
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] > 0) {
NSLog(@"Authentication Failure");
[connection cancel];
}
else
{
NSURLCredential *credential = [NSURLCredential credentialWithUser:self.username
password:self.password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
}
I think the completionHandler method is for basic requests. Maybe you could consider using AFNetworking as I use this with block methods and authentication.
EDIT....
Have you tried adding the authentication header to the NSURLRequest?
Create an NSMutableURLRequest:
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.example.com/"]];
And add the authentication header like this:
NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", userName, password];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)];
[urlRequest setValue:authValue forHTTPHeaderField:@"Authorization"];
The AFBase64EncodedStringFromString function is this:
static NSString * AFBase64EncodedStringFromString(NSString *string) {
NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSUInteger length = [data length];
NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *input = (uint8_t *)[data bytes];
uint8_t *output = (uint8_t *)[mutableData mutableBytes];
for (NSUInteger i = 0; i < length; i += 3) {
NSUInteger value = 0;
for (NSUInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
NSUInteger idx = (i / 3) * 4;
output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F];
output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F];
output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '=';
output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding];
}
Then call the function you called before, but using your new NSURLRequest:
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
}];
Even though the issue is solved a while now, I want to add a solution that doesn`t require 3rd party libraries:
//HTTP Authentication
NSString *authStr = [NSString stringWithFormat:@"%@:%@", @"Username", @"Password"]];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [authData base64Encoding];
//Set up Request:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
[request setURL:[NSURL URLWithString:url]];
//...
// Pack in the user credentials
[request setValue:[NSString stringWithFormat:@"Basic %@",authValue] forHTTPHeaderField:@"Authorization"];
// Send the asynchronous request as usual
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *responseCode, NSData *responseData, NSError *error) {
// Do stuff..
}
NSURLConnection is deprecated in iOS 9, try this code which is from LazyTableImages example from here [https://developer.apple.com/library/ios/samplecode/LazyTableImages/Introduction/Intro.html][1]
@property (nonatomic, strong) NSURLSessionDataTask *sessionTask;
//somwere in your code
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL URLWithString:self.postLink] ];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:60];
[request setHTTPMethod:@"POST"];
[request addValue:[[NSUserDefaults standardUserDefaults] objectForKey:@"token"]
forHTTPHeaderField:@"ACCESSTOKEN"];
self.sessionTask = [[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//do completion staff here
}];