我可以使用NSURLCredentialStorage进行HTTP基本authentication吗?

我有一个可用类,我想用来连接到我正在build立的REST风格的Web服务。 我已经决定在我的PHP后端使用HTTP基本身份validation,就像这样…

<?php if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); //Stuff that users will see if they click 'Cancel' exit; } else { //Validation Code echo "You entered info."; } ?> 

在这一点上,我正在使用一个同步的NSURLConnection,我知道苹果文档状态有较less的authentication支持。

但是甚至可以呢? 我可以做cookievalidation非常容易sANSURLProtectionSpaces或NSURLCredentials或任何身份validation类。 另外,是否有任何资源,我可以阅读更多关于Cocoaauthentication类?

谢谢。

更新:mikeabdullahuk你提供的代码(第二个例子)与我写的代码几乎相同。 我做了一些更多的调查,发现NSURLConnection正在返回一个错误…

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

该代码对应于NSURLErrorUserCancelledAuthentication。 所以显然我的代码没有访问NSURLCredentialStorage,而是取消了身份validation。 这可能与PHP HTTP身份validationfunction有关吗? 我现在很困惑。

同步的NSURLConnection绝对可以与NSURLCredentialStorage一起NSURLCredentialStorage 。 以下是通常的工作方式:

  1. NSURLConnection从服务器请求页面
  2. 服务器回复401响应
  3. NSURLConnection看起来可以从URL中收集到什么凭证
  4. 如果URL没有提供完整的凭据(用户名和密码), NSURLConnection也会咨询NSURLCredentialStorage来填补空缺
  5. 如果完整凭证尚未确定, NSURLConnection将发送-connection:didReceiveAuthenticationChallenge:委托方法要求凭证
  6. 如果NSURLConnection现在最终具有完整凭据,则会重试原始请求,包括授权数据。

通过使用同步连接方法,您只能在步骤5中失去提供自定义身份validation的能力。 因此,您可以在URL中预先提供身份validation凭据,也可以在发送请求之前将其放置在NSURLCredentialStorage 。 例如

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

要么:

 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]; 

在401或其他身份validation质询不可接受/不可能的情况下,我有时会使用虚拟CFHTTPMessage生成validation行,然后将其复制回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"]; 

这似乎完全是一个奇怪的方式来做到这一点,但它是宽容的情况下,用户名/密码不是URL干净的和NSURLRequest拒绝咨询NSURLCredentialStorage,因为服务器实际上并没有发送HTTP 401(例如它发送一个普通的页面)。

我会注意到mikeabdullahuk的答案是好的,但是如果你使用NSURLCredentialPersistencePermanent而不是每个会话,它将把用户钥匙串中的证书存储下来,所以下一次你可以检查NSURLCredentialStorage是否有一个非零值用于保护空间的缺省凭证,如果你得到一个非零的价值,你可以只是通过凭证。我现在正在使用这个方法为我写一个delicious.com客户端,它在我的testing中工作得很好。

将您的凭据设置为保护空间的默认凭据:

 // 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]; 

此时,使用与您设置的保护空间相匹配的任何后续NSURLConnection都将使用此凭据