我有一个 iOS 应用程序,它将向网站提交用户名和密码,并检索按“登录”后加载的网页的 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&ageUniqueId=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"OST"];
[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)connectionNSURLConnection *)connection didReceiveAuthenticationChallengeNSURLAuthenticationChallenge *)challenge {
NSLog(@"HEREEE");
if ([challenge previousFailureCount] == 0) {
NSLog(@"received authentication challenge");
NSURLCredential *newCredential = [NSURLCredential credentialWithUser"USERNAME"
password"ASSWORD"
persistence:NSURLCredentialPersistenceForSession];
NSLog(@"credential created");
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
NSLog(@"responded to authentication challenge");
}
else {
NSLog(@"previous authentication failure");
}
}
但是这个方法永远不会被调用!
我的 View Controller 符合:
NSURLConnectionDelegate,NSURLAuthenticationChallengeSender,NSURLConnectionDataDelegate
谢谢!
Best Answer-推荐答案 strong>
一些想法:
我对 __VIEWSTATE 和 __EVENTVALIDATION 中存在保留字符感到惊讶。根据 the x-www-form-urlencoded spec , 你应该使用百分比转义字符而不是 * , - , . , 0 -9 、A -Z 、_ 和 a -z 。
POST 值的标准百分比转义例程是:
- (NSString *)percentEscapeStringNSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)@" ",
(CFStringRef)@":/?@!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString" " withString"+"];
}
我不确定这是否严重,但您缺少 = 个字符。所以,我希望 __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
请注意整个请求正文中出现的百分比转义。我通过查看 Charles 中的请求确定了正文.
我很惊讶地看到 __VIEWSTATE 、__EVENTVALIDATION 和 PageUniqueId 是这样硬编码的。我可以很容易地想象,对这些变量使用固定值会有问题。这完全取决于网站的编程方式。我收集到您正在尝试以编程方式访问不是 Web 服务而是 HTML 界面的网站,这可能会出现问题。
在尝试登录之前,您可能必须先使用 Logins.aspx 执行 GET 请求,然后从初始登录 HTML 中解析这些值。在尝试以编程方式与 Web 服务器交互时,您必须小心调用 Web 浏览器会调用的所有页面,因为您的应用也应该使用这样的服务器状态变量。
不相关,但您不需要指定 Content-length ,因为 NSURLConnection 会根据您的 大小为您提供>httpBody .
如果您使用 didReceiveAuthenticationChallenge ,请注意您应确保 else 子句调用 cancelAuthenticationChallenge 或continueWithoutCredentialForAuthenticationChallenge 。您总是必须调用这三种挑战方法之一。
话虽如此,但根本不清楚 didReceiveAuthenticationChallenge 是否会被调用。您的服务器可能正在使用一些不基于质询的服务器应用级身份验证。
归根结底,我们很难根据迄今为止提供的信息来诊断问题的根源。我会联系HTML界面的作者,询问认证过程的细节。
关于ios - NSURLConnection 和 NSMutableURLRequest 身份验证,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/23398368/
|