我有一个 iOS 应用程序,它将向网站提交用户名和密码,并检索按“登录”后加载的网页的 HTML 代码:https://grades.bsd405.org/Pinnacle/Gradebook/Logon.aspx ?
表单数据字段如下:
__LASTFOCUS、__EVENTTARGET、__EVENTARGUMENT、__VIEWSTATE、__EVENTVALIDATION、ctl00$ContentPlaceHolder$用户名、ctl00$ContentPlaceHolder$密码、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");
}
但是这个方法永远不会被调用!
我的 View Controller 符合:
NSURLConnectionDelegate,NSURLAuthenticationChallengeSender,NSURLConnectionDataDelegate
谢谢!
最佳答案
几个想法:
令我惊讶的是
__VIEWSTATE
和__EVENTVALIDATION
中存在保留字符。每thex-www-form-urlencoded
spec , 你应该是*
,-
,.
,0
-9< 以外的转义字符百分比
、A
-Z
、_
和a
-z
。POST
值的标准百分比转义例程是:- (NSString *)percentEscapeString:(NSString *)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
会根据您的的大小为您提供>http正文
。如果您要使用
didReceiveAuthenticationChallenge
,请注意您应确保else
子句调用cancelAuthenticationChallenge
或continueWithoutCredentialForAuthenticationChallenge
。您必须始终调用这三种挑战方法中的一种。话虽如此,尚不清楚
didReceiveAuthenticationChallenge
是否会被调用。您的服务器可能正在使用一些非基于质询的服务器应用程序级身份验证。
归根结底,我们很难根据目前提供的内容来诊断问题的根源。我会联系 HTML 界面的作者并询问身份验证过程的细节。
关于ios - NSURLConnection 和 NSMutableURLRequest 认证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23398368/