NSURLConnection不使用默认凭据

时间:2012-02-21 14:28:31

标签: ios nsurlconnection nsurlcredential

我尝试使用NSURLConnectionhttp://cmis.demo.nuxeo.org/nuxeo/atom/cmis/建立联系。此演示Web服务documented需要身份验证(登录:管理员/密码:管理员)。

修改:此网络服务现在会发送身份验证质询,但问题时尚未发出。

此网络服务发送身份验证质询,因此我无法使用connection:didReceiveAuthenticationChallenge:委托方法。相反,我在共享凭证存储中设置了默认NSURLCredential。遗憾的是,NSURLConnection未使用此默认凭据。

这是我的代码(使用ARC,在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

由于未使用默认凭据,因此我收到html(登录页面)而不是xml。如果我将manuallyAddAuthorizationHeader变量设置为YES,则授权有效,我会收到xml。

我的问题是:NSURLConnection为什么不自动使用默认的NSURLCredential

3 个答案:

答案 0 :(得分:8)

在没有身份验证质询的情况下发送默认凭据被认为是不安全的,尤其是在您通过纯HTTP进行通信的情况下。 HTTP规范说明可以主动发送凭据,但您通常应该等待身份验证质询。这就是Cocoa默认提供的行为。

如果您需要主动发送凭据,则必须自己手动添加标头。您可以自己进行base-64编码,也可以使用CFHTTP函数为您执行此操作,如下所示:

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

然后,只需将authorizationString设置为Authorization中的NSURLRequest标题。

(代码是从https://stackoverflow.com/a/509480/100478公然复制的,虽然我自己多次写过类似的代码。)

答案 1 :(得分:3)

由于HTTP支持许多不同的身份验证方法(Basic,Digest,Kerberos等),NSURLConnection无法在从服务器收到身份验证质询之前发送凭据,因为它不知道如何发送它们。 / p>

答案 2 :(得分:0)

虽然BJ的答案可以在客户端解决您的问题,但真正的问题是服务器。 NSURLConnection内部将使用它自己的委托方法connection:didReceiveAuthenticationChallenge:和其他身份验证方法。这是它可以从NSURLCredentialStorage查找可以应用的凭证的位置。在你的情况下,这似乎并没有发生。对于要调用的方法,服务器不仅必须提供40x HTTP状态代码,而且必须包含WWW-Authenticate标头。这告诉NSURLConnection尝试回答身份验证质询。您的服务器可能不包含此内容,这就是客户端不发送凭据的原因。