NSURL-verbinding en basis HTTP-authenticatie in iOS

Ik moet een eerste GET HTTP requestaanroepen met Basis Authentication. Dit zou de eerste keer zijn dat het verzoek naar de server wordt verzonden en ik heb al de username & passworddus er is geen uitdaging van de server nodig voor autorisatie.

Eerste vraag:

  1. Moet NSURLConnectionworden ingesteld als synchroon om Basisverificatie uit te voeren? Volgens het antwoord op deze postlijkt het erop dat je geen basisverificatie kunt uitvoeren als u kiest voor de asynchrone route.

  2. Iedereen kent een voorbeeldcode die de basisverificatie illustreert op een GET requestzonder dat er een uitdagingsreactie nodig is? Apple-documentatietoont een voorbeeld, maar alleen nadat de server het challenge-verzoek aan de client heeft verzonden.

Ik ben een beetje nieuw in het netwerkgedeelte van de SDK en ik weet niet zeker welke van de andere klassen ik moet gebruiken om dit werkend te krijgen. (Ik zie de klasse NSURLCredential, maar het lijkt erop dat deze alleen wordt gebruikt met NSURLAuthenticationChallengenadat de client een geautoriseerde bron van de server heeft aangevraagd).


Antwoord 1, autoriteit 100%

Ik gebruik een asynchrone verbinding met MGTwitterEngineen het stelt de autorisatie in de NSMutableURLRequest(theRequest) als volgt in:

NSString *authStr = [NSString stringWithFormat:@"%@:%@", [self username], [self password]];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]];
[theRequest setValue:authValue forHTTPHeaderField:@"Authorization"];

Ik geloof niet dat deze methode de uitdagingslus vereist, maar ik kan het mis hebben


Antwoord 2, autoriteit 60%

Zelfs de vraag is beantwoord, ik wil de oplossing presenteren, waarvoor geen externe bibliotheken nodig zijn, vond ik in een andere thread:

// Setup NSURLConnection
NSURL *URL = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:URL
                                         cachePolicy:NSURLRequestUseProtocolCachePolicy
                                     timeoutInterval:30.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[connection release];
// NSURLConnection Delegates
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge previousFailureCount] == 0) {
        NSLog(@"received authentication challenge");
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:@"USER"
                                                                    password:@"PASSWORD"
                                                                 persistence:NSURLCredentialPersistenceForSession];
        NSLog(@"credential created");
        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
        NSLog(@"responded to authentication challenge");    
    }
    else {
        NSLog(@"previous authentication failure");
    }
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    ...
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    ...
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    ...
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    ...
}

Antwoord 3, autoriteit 10%

Hier is een gedetailleerd antwoord zonder dat een derde partij erbij betrokken is:

Kijk hier:

//username and password value
NSString *username = @“your_username”;
NSString *password = @“your_password”;
//HTTP Basic Authentication
NSString *authenticationString = [NSString stringWithFormat:@"%@:%@", username, password]];
NSData *authenticationData = [authenticationString dataUsingEncoding:NSASCIIStringEncoding];
NSString *authenticationValue = [authenticationData base64Encoding];
//Set up your request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.your-api.com/“]];
// Set your user login credentials
[request setValue:[NSString stringWithFormat:@"Basic %@", authenticationValue] forHTTPHeaderField:@"Authorization"];
// Send your request asynchronously
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *responseCode, NSData *responseData, NSError *responseError) {
      if ([responseData length] > 0 && responseError == nil){
            //logic here
      }else if ([responseData length] == 0 && responseError == nil){
             NSLog(@"data error: %@", responseError);
             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Error accessing the data" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
             [alert show];
             [alert release];
      }else if (responseError != nil && responseError.code == NSURLErrorTimedOut){
             NSLog(@"data timeout: %@”, NSURLErrorTimedOut);
             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"connection timeout" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
             [alert show];
             [alert release];
      }else if (responseError != nil){
             NSLog(@"data download error: %@”,responseError);
             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"data download error" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
             [alert show];
             [alert release];
      }
}]

Laat me alsjeblieft je feedback hierover weten.

Bedankt


Antwoord 4, autoriteit 5%

Als u niet de hele MGTwitterEngine wilt importeren en u doet geen asynchroon verzoek
Dan kunt u gebruik maken van
http://www.chrisumbel.com/article/basic_authentication_iphone_cocoa_touch

De gebruikersnaam en het wachtwoord coderen met base64
Dus vervang

NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]];

met

NSString *encodedLoginData = [Base64 encode:[loginString dataUsingEncoding:NSUTF8StringEncoding]];

na

u moet het volgende bestand opnemen

static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@implementation Base64
+(NSString *)encode:(NSData *)plainText {
    int encodedLength = (((([plainText length] % 3) + [plainText length]) / 3) * 4) + 1;
    unsigned char *outputBuffer = malloc(encodedLength);
    unsigned char *inputBuffer = (unsigned char *)[plainText bytes];
    NSInteger i;
    NSInteger j = 0;
    int remain;
    for(i = 0; i < [plainText length]; i += 3) {
        remain = [plainText length] - i;
        outputBuffer[j++] = alphabet[(inputBuffer[i] & 0xFC) >> 2];
        outputBuffer[j++] = alphabet[((inputBuffer[i] & 0x03) << 4) | 
                                     ((remain > 1) ? ((inputBuffer[i + 1] & 0xF0) >> 4): 0)];
        if(remain > 1)
            outputBuffer[j++] = alphabet[((inputBuffer[i + 1] & 0x0F) << 2)
                                         | ((remain > 2) ? ((inputBuffer[i + 2] & 0xC0) >> 6) : 0)];
        else 
            outputBuffer[j++] = '=';
        if(remain > 2)
            outputBuffer[j++] = alphabet[inputBuffer[i + 2] & 0x3F];
        else
            outputBuffer[j++] = '=';            
    }
    outputBuffer[j] = 0;
    NSString *result = [NSString stringWithCString:outputBuffer length:strlen(outputBuffer)];
    free(outputBuffer);
    return result;
}
@end

Antwoord 5, autoriteit 2%

Aangezien NSData::dataUsingEncoding verouderd is (ios 7.0), kunt u deze oplossing gebruiken:

// Forming string with credentials 'myusername:mypassword'
NSString *authStr = [NSString stringWithFormat:@"%@:%@", username, password];
// Getting data from it
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
// Encoding data with base64 and converting back to NSString
NSString* authStrData = [[NSString alloc] initWithData:[authData base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithLineFeed] encoding:NSASCIIStringEncoding];
// Forming Basic Authorization string Header
NSString *authValue = [NSString stringWithFormat:@"Basic %@", authStrData];
// Assigning it to request
[request setValue:authValue forHTTPHeaderField:@"Authorization"];

Antwoord 6

Als u GTMHTTPFetchergebruikt voor uw verbinding, is basisverificatie redelijk makkelijk ook. U hoeft alleen de inloggegevens aan de ophaler te verstrekken voordat u met het ophalen begint.

NSString * urlString = @"http://www.testurl.com/";
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
NSURLCredential * credential = [NSURLCredential credentialWithUser:@"username" password:@"password" persistence:NSURLCredentialPersistenceForSession];
GTMHTTPFetcher * gFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
gFetcher.credential = credential;
[gFetcher beginFetchWithDelegate:self didFinishSelector:@selector(fetchCompleted:withData:andError:)];

Antwoord 7

Kun je me vertellen wat de reden is achter het beperken van de lengte van de coderingsregel tot 80 in je voorbeeldcode? Ik dacht dat HTTP-headers een maximale lengte hebben van ongeveer 4k (of misschien doen sommige servers er niet langer over). – Justin Galzic 29 december ’09 om 17:29

Het is niet beperkt tot 80, het is een optie van de methode base64EncodingWithLineLength in NSData+Base64.h/m, waar je je gecodeerde string in meerdere regels kunt splitsen, wat handig is voor andere toepassingen, zoals nntp-transmissie. Ik geloof dat 80 door de auteur van de Twitter-engine is gekozen als een lengte die groot genoeg is om de meeste door gebruikers/wachtwoord gecodeerde resultaten op één regel te plaatsen.


Antwoord 8

Je kunt AFNetworkinggebruiken (het is opensource), hier is code die werkte voor mij. Deze code verzendt bestand met basisverificatie. Verander gewoon de url, e-mail en wachtwoord.

NSString *serverUrl = [NSString stringWithFormat:@"http://www.yoursite.com/uploadlink", profile.host];
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:serverUrl parameters:nil error:nil];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
// Forming string with credentials 'myusername:mypassword'
NSString *authStr = [NSString stringWithFormat:@"%@:%@", email, emailPassword];
// Getting data from it
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
// Encoding data with base64 and converting back to NSString
NSString* authStrData = [[NSString alloc] initWithData:[authData base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithLineFeed] encoding:NSASCIIStringEncoding];
// Forming Basic Authorization string Header
NSString *authValue = [NSString stringWithFormat:@"Basic %@", authStrData];
// Assigning it to request
[request setValue:authValue forHTTPHeaderField:@"Authorization"];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSURL *filePath = [NSURL fileURLWithPath:[url path]];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:^(NSProgress * _Nonnull uploadProgress) {
// This is not called back on the main queue.
// You are responsible for dispatching to the main queue for UI updates
     dispatch_async(dispatch_get_main_queue(), ^{
                //Update the progress view
                LLog(@"progres increase... %@ , fraction: %f", uploadProgress.debugDescription, uploadProgress.fractionCompleted);
            });
        } completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
            if (error) {
                NSLog(@"Error: %@", error);
            } else {
                NSLog(@"Success: %@ %@", response, responseObject);
            }
        }];
[uploadTask resume];

Other episodes