NSURLConnection和NSMutableURLRequest身份验证

时间:2014-04-30 21:29:53

标签: ios objective-c http nsurl

我有一个iOS应用程序,它会向网站提交用户名和密码,并检索网页的 HTML 代码,该代码在按下'登录':{{后加载3}}?

表单数据字段如下:

__LASTFOCUS, __EVENTTARGET, __EVENTARGUMENT, __VIEWSTATE, __EVENTVALIDATION, ctl00$ContentPlaceHolder$Username, ctl00$ContentPlaceHolder$Password, ctl00$ContentPlaceHolder$lstDomains, ctl00$ContentPlaceHolder$LogonButton, PageUniqueId

这是我到目前为止的代码:

NSURL * url = [NSURL URLWithString:@" https://grades.bsd405.org/Pinnacle/Gradebook/Logon.aspx"];

NSString *post = @"__LASTFOCUS&__EVENTTARGET&__EVENTARGUMENT&__VIEWSTATE=/wEPDwUJNTkxNzI3MDIzD2QWAmYPZBYCAgMPZBYGAgEPZBYCAgkPZBYCAgEPZBYIAgMPFgIeB1Zpc2libGVoZAIFDxYCHwBoZAIHDxYCHwBoZAIJDxYCHgVzdHlsZQUjdmVydGljYWwtYWxpZ246bWlkZGxlO2Rpc3BsYXk6bm9uZTtkAgMPDxYCHwBoZGQCBQ9kFghmD2QWAgINDxYCHgVjbGFzcwUQc2luZ2xlU2Nob29sTGlzdBYCAgEPZBYCAgEPEGQPFgFmFgEQBQ5EZWZhdWx0IERvbWFpbgUIUGlubmFjbGVnZGQCAg9kFgICEw9kFgICAQ9kFgICAQ8QZGQWAGQCBw8PFgIeBFRleHQFIFBpbm5hY2xlIEdyYWRlIDIwMTIgV2ludGVyIEJyZWFrZGQCCA8PFgIfAwU3Q29weXJpZ2h0IChjKSAyMDEzIEdsb2JhbFNjaG9sYXIuICBBbGwgcmlnaHRzIHJlc2VydmVkLmRkZP/l6irI9peZfyqpKjk3fwLuEbos&__EVENTVALIDATION=/wEWBgKjnbqUCQLnksmgAQKTpbWbDgLB5+KIBAL4xb20BAK20ZqiCel6sQLBsF1W3XHOxpgq+tJj+Rx2&ctl00$ContentPlaceHolder$Username=TESTUSERNAME&ctl00$ContentPlaceHolder$Password=TESTPASSWORD&ctl00$ContentPlaceHolder$lstDomains=Pinnacle&ctl00$ContentPlaceHolder$LogonButton=Signin&PageUniqueId=2dacba26-bb0d-412f-b06a-e02caf039c4b";

NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];

[self clearCookiesForURL:url];
[request setURL:url];

[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];

NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];

但是,始终会返回错误页面。我究竟做错了什么? 我还实现了以下内容:

-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(@"HEREEE");
if ([challenge previousFailureCount] == 0) {
    NSLog(@"received authentication challenge");
    NSURLCredential *newCredential = [NSURLCredential credentialWithUser:@"USERNAME"
                                                                password:@"PASSWORD"
                                                             persistence:NSURLCredentialPersistenceForSession];
    NSLog(@"credential created");
    [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
    NSLog(@"responded to authentication challenge");
}
else {
    NSLog(@"previous authentication failure");
}

}

但这种方法从未被调用过!

我的视图控制器符合:
    NSURLConnectionDelegate,NSURLAuthenticationChallengeSender,NSURLConnectionDataDelegate

谢谢!

1 个答案:

答案 0 :(得分:1)

有几点想法:

  1. 我对__VIEWSTATE__EVENTVALIDATION中保留字符的存在感到惊讶。根据{{​​3}},您应该转义除*-.0 - 9A以外的字符的百分比 - Z_a - z

    POST值的标准百分比转义例程是:

    - (NSString *)percentEscapeString:(NSString *)string
    { 
        NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                     (CFStringRef)string,
                                                                                     (CFStringRef)@" ",
                                                                                     (CFStringRef)@":/?@!$&'()*+,;=",
                                                                                     kCFStringEncodingUTF8));
        return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    }
    
  2. 我不确定它是否至关重要,但你遗漏了=个字符。因此,我希望__LASTFOCUS&...而不是__LASTFOCUS=&...

    将这两个点拉在一起,得到的有效负载应该类似于:

    __LASTFOCUS=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUJNTkxNzI3MDIzD2QWAmYPZBYCAgMPZBYGAgEPZBYCAgkPZBYCAgEPZBYIAgMPFgIeB1Zpc2libGVoZAIFDxYCHwBoZAIHDxYCHwBoZAIJDxYCHgVzdHlsZQUjdmVydGljYWwtYWxpZ246bWlkZGxlO2Rpc3BsYXk6bm9uZTtkAgMPDxYCHwBoZGQCBQ9kFghmD2QWAgINDxYCHgVjbGFzcwUQc2luZ2xlU2Nob29sTGlzdBYCAgEPZBYCAgEPEGQPFgFmFgEQBQ5EZWZhdWx0IERvbWFpbgUIUGlubmFjbGVnZGQCAg9kFgICEw9kFgICAQ9kFgICAQ8QZGQWAGQCBw8PFgIeBFRleHQFIFBpbm5hY2xlIEdyYWRlIDIwMTIgV2ludGVyIEJyZWFrZGQCCA8PFgIfAwU3Q29weXJpZ2h0IChjKSAyMDEzIEdsb2JhbFNjaG9sYXIuICBBbGwgcmlnaHRzIHJlc2VydmVkLmRkZP%2Fl6irI9peZfyqpKjk3fwLuEbos&__EVENTVALIDATION=%2FwEWBgKjnbqUCQLnksmgAQKTpbWbDgLB5%2BKIBAL4xb20BAK20ZqiCel6sQLBsF1W3XHOxpgq%2BtJj%2BRx2&ctl00%24ContentPlaceHolder%24Username=a&ctl00%24ContentPlaceHolder%24Password=b&ctl00%24ContentPlaceHolder%24lstDomains=Pinnacle&ctl00%24ContentPlaceHolder%24LogonButton=Sign+in&PageUniqueId=a3113b01-cf2f-4081-8a1a-d8557e7347de
    

    请注意在该请求的整个正文中出现的百分比。我通过查看the x-www-form-urlencoded spec中的请求确定了身体。

  3. 我很惊讶地看到__VIEWSTATE__EVENTVALIDATIONPageUniqueId这样硬编码。我很容易想象,对这些变量使用固定值会有问题。这完全取决于网站的编程方式。我正在收集您尝试以编程方式访问不是Web服务的网站,而是HTML界面,这可能会有问题。

    在尝试登录之前,您可能必须首先使用GET执行Logins.aspx请求,并从初始登录HTML解析这些值。当尝试以编程方式与Web服务器交互时,您必须小心地调用Web浏览器所有的页面,因为这样的服务器状态变量也应该是您的应用程序应该使用的。

    < / LI>
  4. 不相关,但您无需指定Content-length,因为NSURLConnection会根据httpBody的大小为您提供。{/ p>

  5. 如果您开始使用didReceiveAuthenticationChallenge,请注意您应确保else子句调用cancelAuthenticationChallengecontinueWithoutCredentialForAuthenticationChallenge。你总是要调用这三种挑战方法中的一种。

    话虽如此,但根本不会调用didReceiveAuthenticationChallenge。您的服务器可能正在使用一些不是基于挑战的服务器应用级身份验证。

  6. 总而言之,我们很难根据迄今为止提供的内容来诊断问题的根源。我会联系HTML界面的作者并询问身份验证过程的具体细节。