NSURLConnection和NSMutableURLRequestvalidation

我有一个iOS应用程序,它将提交用户名和密码到一个网站,并检索按下“login”后加载的网页的HTML代码: https : //grades.bsd405.org/Pinnacle/Gradebook/Logon.aspx ?。

表单数据字段如下:

__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?ReturnUrl=%2fPinnacle%2fGradebook%2fDefault.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. 我对__VIEWSTATE__EVENTVALIDATION的保留字符的存在感到惊讶。 根据x-www-form-urlencoded规范 ,你应该是除了*- ,以外的字符百分比转义字符.09AZ_az

    我的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 =尖峰&ctl00%24ContentPlaceHolder%24LogonButton =拍+在&PageUniqueId = a3113b01- cf2f-4081-8a1a-d8557e7347de
    

    请注意,在该请求的正文中出现了百分比转义。 我通过查看查尔斯的请求来确定身体。

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

    在尝试login之前,您可能必须首先使用Logins.aspx执行GET请求,然后从初始loginHTMLparsing这些值。 当试图以编程方式与Web服务器进行交互时,必须小心地调用Web浏览器所有的页面,因为将会有这样的服务器状态variables,您的应用程序也应该使用它们。

  4. 不相关,但是你不需要指定Content-length ,因为NSURLConnection会根据你的httpBody的大小为你httpBody

  5. 如果您已经到了使用cancelAuthenticationChallenge的地步,请注意您应该确保else子句调用cancelAuthenticationChallenge或者continueWithoutCredentialForAuthenticationChallenge cancelAuthenticationChallenge 。 你总是要打三种挑战方法之一。

    话虽如此,目前还不清楚didReceiveAuthenticationChallenge会被调用。 您的服务器可能会采用一些不是基于挑战的服务器应用程序级别身份validation。

底线,我们很难根据迄今为止提供的内容来诊断问题的根源。 我会联系HTML界面的作者,询问authentication过程的细节。