Objective c 我可以使用NSURLCredentialStorage进行HTTP基本身份验证吗?
我有一个cocoa类,我想用它连接到我正在构建的RESTful web服务。我决定在我的PHP后端使用HTTP基本身份验证,就像这样Objective c 我可以使用NSURLCredentialStorage进行HTTP基本身份验证吗?,objective-c,cocoa,http,authentication,https,Objective C,Cocoa,Http,Authentication,Https,我有一个cocoa类,我想用它连接到我正在构建的RESTful web服务。我决定在我的PHP后端使用HTTP基本身份验证,就像这样 <?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 t
<?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.";
}
?>
该代码对应于NSURErrorUserCancelledAuthentication。显然,我的代码没有访问NSURLCresidentialstorage,而是取消了身份验证。这可能与PHP HTTP身份验证函数有关吗?这一点我很困惑。同步
nsurl连接
绝对可以与NSURLCredentialStorage
一起使用。事情通常是这样的:
NSURLConnection
从服务器请求页面NSURLConnection
查看它可以从URL收集哪些凭据NSURLConnection
也将查阅NSURLCredentialStorage
,以填补空白NSURLConnection
将发送请求凭据的-connection:didReceiveAuthenticationChallenge:
委托方法NSURLConnection
现在终于拥有完整凭据,它将重试原始请求,包括授权数据NSURLCredentialStorage
中。e、 g
NSURLRequest *request =
[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://user:pass@example.com"]];
[NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
或:
我会注意到Mikeabullahuk的答案是好的,但是如果您使用NSURCredentialPersistencePermanent而不是每个会话,它会将凭据存储在用户密钥链中,以便下次您可以检查NSURCredentialStorage以获取保护空间的默认凭据的非零值,如果您获得非零值,则可以传递中的凭据。我现在正在为我正在编写的delicious.com客户端使用此方法,它在我的测试中运行得非常好。在401或其他身份验证挑战不可接受/不可能的情况下,我有时会使用伪CFHTTPMessage生成身份验证行,然后将其复制回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拒绝查询NSURLCresidentialstorage的情况,因为服务器实际上没有发送HTTP 401(例如,它发送一个常规页面).将您的凭据设置为保护空间的默认凭据:
// 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都将使用此凭据我刚才遇到了这个问题。我对ObjectiveC非常陌生,但我想知道是否有任何对象(特别是凭据和保护空间)必须发布。顺便说一句,我在一个异步调用(initWithRequest)上实现了这个方法,但仍然得到了didReceiveAuthenticationChallenge回调。@Bill,protectionSpace确实需要释放,如果在生产代码中使用,就像我使用的+alloc一样。必须释放protectionSpace。alloc将返回retainCount==1的对象,因此在[…setDefaultCredential:…]之后,您应该像[protectionSpace release]一样释放它;NSURLCresidentialstorage对我来说不起作用,但只需在http字符串中加上user:pass作为服务器前缀就行了,非常感谢,这是一个超级简单的解决方案。根据sendSynchronousRequest的苹果文档:“如果下载请求需要身份验证,必须将所需的凭据指定为URL的一部分…“我自己的经验可以证实这一点;也就是说,使用NSURLCRedentialStorage与sendSynchronousRequest不兼容。谢谢!在不需要委托模式的情况下,它特别有用。
// 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"];
// 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];