Domanda

Sto cercando di connettermi http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ insieme a NSURLConnection. Questo servizio Web demo è documentato Per richiedere l'autenticazione (accesso: amministratore / password: amministratore).

Modificare: Questo servizio Web ora invia una sfida di autenticazione, non era al momento della domanda.

Questo servizio web non Invia una sfida di autenticazione, quindi non posso usare il connection:didReceiveAuthenticationChallenge: Metodo delegato. Invece ho impostato un valore predefinito NSURLCredential Nell'archiviazione delle credenziali condivise. Sfortunatamente, questa credenziale predefinita non viene utilizzata da NSURLConnection.

Ecco il mio codice (usando ARC, testato su iOS 5):

@implementation ViewController
{
    NSMutableData *responseData;
}

- (IBAction) connect:(id)sender
{
    NSString *user = @"Administrator";
    NSString *password = @"Administrator";
    NSURL *nuxeoURL = [NSURL URLWithString:@"http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/"];

    NSURLCredential *credential = [NSURLCredential credentialWithUser:user password:password persistence:NSURLCredentialPersistenceForSession];
    NSString *host = [nuxeoURL host];
    NSNumber *port = [nuxeoURL port];
    NSString *protocol = [nuxeoURL scheme];
    NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:host port:[port integerValue] protocol:protocol realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic];
    [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:nuxeoURL];
    BOOL manuallyAddAuthorizationHeader = NO;
    if (manuallyAddAuthorizationHeader)
    {
        NSData *authoritazion = [[NSString stringWithFormat:@"%@:%@", user, password] dataUsingEncoding:NSUTF8StringEncoding];
        NSString *basic = [NSString stringWithFormat:@"Basic %@", [authoritazion performSelector:@selector(base64Encoding)]];
        [request setValue:basic forHTTPHeaderField:@"Authorization"];
    }
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [connection start];
}

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    responseData = [NSMutableData data];
}

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [responseData appendData:data];
}

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"connectionDidFinishLoading:%@", connection);
    NSLog(@"%@", [[NSString alloc] initWithData:responseData encoding:NSISOLatin1StringEncoding]);
}

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

@end

Poiché la credenziale predefinita non viene utilizzata, ricevo HTML (pagina di accesso) anziché XML. Se imposto il manuallyAddAuthorizationHeader variabile a YES, quindi le opere di autorizzazione e ricevo XML.

La mia domanda è: perché lo fa NSURLConnection non automaticamente Usa il valore predefinito NSURLCredential?

È stato utile?

Soluzione

L'invio delle credenziali predefinite senza una sfida di autenticazione è considerata insicura, soprattutto nel caso in cui si comunichi su HTTP semplice. La specifica HTTP dice che tu Potere Invia credenziali in modo proattivo, ma di solito dovresti aspettare una sfida di autenticazione. E questo è il comportamento che il cacao fornisce per impostazione predefinita.

Se hai bisogno di inviare in modo proattivo le credenziali, dovrai aggiungere manualmente le intestazioni da solo. Puoi solo base-64 codificarlo da solo, oppure puoi usare il CFHTTP funziona per farlo per te, così:

CFHTTPMessageRef dummyRequest =
    CFHTTPMessageCreateRequest(
        kCFAllocatorDefault,
        CFSTR("GET"),
        (CFURLRef)[urlRequest URL],
        kCFHTTPVersion1_1);
CFHTTPMessageAddAuthentication(
    dummyRequest,
    nil,
    (CFStringRef)username,
    (CFStringRef)password,
    kCFHTTPAuthenticationSchemeBasic,
    FALSE);
authorizationString =
    (NSString *)CFHTTPMessageCopyHeaderFieldValue(
        dummyRequest,
        CFSTR("Authorization"));
CFRelease(dummyRequest);

Quindi basta impostare il authorizationString come la Authorization intestazione nel tuo NSURLRequest.

(Codice copiato palesemente da https://stackoverflow.com/a/509480/100478, sebbene io abbia scritto un codice simile da solo molte volte.)

Altri suggerimenti

Poiché HTTP supporta molti diversi metodi di autenticazione (base, digest, kerberos, ecc.), NSURLConnection Impossibile inviare le credenziali prima di ricevere la sfida di autenticazione dal server perché non sa come inviarle.

Mentre la risposta di BJ può risolvere il tuo problema sul lato client, il problema reale è il server. Internamente NsurlConnection utilizzerà il proprio equivalente del metodo delegato connection:didReceiveAuthenticationChallenge: e gli altri metodi di autenticazione. Qui è da dove può applicare una credenziale NSURLCredentialStorage . Nel tuo caso questo non sembra accadere. Per questi metodi da invocare il server non solo deve fornire un codice di stato HTTP 40x, ma deve includere un'intestazione www-autenticata. Questo dice a NsurlConnection di tentare di rispondere alla sfida di autenticazione. È probabile che il tuo server non includa questo, ed è per questo che il client non sta inviando credenziali.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top