¿Puedo usar NSURLCredentialStorage para autenticación básica HTTP?

Tengo una clase Cocoa configurada que quiero usar para conectarme a un servicio web RESTful que estoy creando. Decidí usar autenticación básica HTTP en mi back-end PHP así …

 

En este punto estoy usando un NSURLConnection síncrono, que entiendo que la documentación de Apple indica que tiene menos soporte para la Autenticación.

Pero, ¿es posible? Puedo hacer autenticación de cookies muy fácilmente sin NSURLProtectionSpaces o NSURLCredentials o cualquiera de las clases de autenticación. Además, ¿hay algún recurso donde pueda leer más sobre las clases de Autenticación Cocoa?

Gracias.

ACTUALIZACIÓN: mikeabdullahuk El código que proporcionó (el segundo ejemplo) es casi idéntico a lo que había escrito. He investigado un poco más y descubrí que NSURLConnection está devolviendo un error …

 Error Domain=NSURLErrorDomain Code=-1012 UserInfo=0x1a5170 "Operation could not be completed. (NSURLErrorDomain error -1012.)" 

El código corresponde a NSURLErrorUserCancelledAuthentication. Aparentemente, mi código no está accediendo a NSURLCredentialStorage y en su lugar está cancelando la autenticación. ¿Podría esto tener algo que ver con las funciones de Autenticación HTTP de PHP? Estoy bastante confundido en este punto.

Una NSURLConnection síncrona NSURLConnection absolutamente con NSURLCredentialStorage . Así es como funcionan las cosas:

  1. NSURLConnection solicita la página del servidor
  2. El servidor responde con una respuesta 401
  3. NSURLConnection busca ver qué credenciales puede obtener de la URL
  4. Si la URL no proporciona las credenciales completas (nombre de usuario y contraseña), NSURLConnection también consultará con NSURLCredentialStorage para completar las lagunas
  5. Si todavía no se han determinado las credenciales completas, NSURLConnection enviará el -connection:didReceiveAuthenticationChallenge: método de delegado que solicita credenciales
  6. Si el NSURLConnection ahora finalmente tiene credenciales completas, reintenta la solicitud original, incluidos los datos de autorización.

Al usar el método de conexión síncrona, solo pierde en el paso 5, la capacidad de proporcionar autenticación personalizada. Por lo tanto, puede proporcionar previamente las credenciales de autenticación en la URL o colocarlas en NSURLCredentialStorage antes de enviar la solicitud. p.ej

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://user:pass@example.com"]]; [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL]; 

o:

 NSURLCredential *credential = [NSURLCredential credentialWithUser:@"user" password:@"pass" persistence:NSURLCredentialPersistenceForSession]; NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"example.com" port:0 protocol:@"http" realm:nil authenticationMethod:nil]; [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace]; [protectionSpace release]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL]; 

En una situación en la que un desafío 401 u otro desafío de autenticación es inaceptable / imposible, a veces uso un CFHTTPMessage ficticio para generar la línea de autenticación, luego copio eso de nuevo en NSURLRequest:

 // assume NSString *username and *password exist and NSURLRequest *urlRequest // exists and is fully configured except for HTTP Basic Authentication.. 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); [urlRequest setValue:authorizationString forHTTPHeaderField:@"Authorization"]; 

Esto puede parecer una forma completamente extraña de hacerlo, pero es tolerante a situaciones en las que el nombre de usuario / contraseña no son URL clean y donde NSURLRequest se niega a consultar NSURLCredentialStorage porque el servidor no está realmente enviando un HTTP 401 (por ejemplo, envía una página regular en su lugar).

Me gustaría señalar que la respuesta de mikeabdullahuk es buena, pero también si usas NSURLCredentialPersistencePermanent en lugar de por sesión guardará las credenciales en el llavero de los usuarios, así que la próxima vez puedes verificar NSURLCredentialStorage para un valor no nulo para las credenciales predeterminadas para un espacio de protección y si obtienes un valor no nulo puede pasar las credenciales. Estoy usando este método ahora mismo para un cliente delicious.com que estoy escribiendo y funciona muy bien en mis pruebas.

Establezca su credencial como la credencial predeterminada para el espacio de protección:

 // Permananent, session, whatever. NSURLCredential *credential = [NSURLCredential credentialWithUser:username password:password persistence: NSURLCredentialPersistencePermanent]; // Make sure that if the server you are accessing presents a realm, you set it here. NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"blah.com" port:0 protocol:@"http" realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; // Store it [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace]; 

En este punto, cualquier NSURLConnection subsiguiente que se impugne utilizando un espacio de protección que coincida con lo que configure utilizará esta credencial