Не удается получить запрос JSON через HTTPS из-за ненадежного сертификата
Я часами гуглял эту проблему, и не могу найти решение.
Последнее учебное пособие, которым я следовал, было этим учебным пособием, объясняющим, как я могу отправить запрос JSON через ненадежное SSL-соединение (в данном случае самозаверяющий сертификат).
Короче говоря, код, который я пробовал до сих пор, это:
Этот метод проверяет, является ли токен действительным с моим веб-API:
-(BOOL)linked
{
if([self token] == nil)
{
return NO;
}else
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?token=%@&object=User&action=check_authorized", SPAtajosApiLink, [self token], nil]];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setHTTPMethod:@"POST"];
NSLog(@"%@", req);
[req setHTTPBody: [mandatoryParameters dataUsingEncoding: NSUTF8StringEncoding]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:req delegate:self];
[connection start];
NSDictionary *validity = [NSJSONSerialization
JSONObjectWithData:[NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil]
options:NSJSONReadingMutableContainers
error:nil];
NSLog(@"RESPONSE LINKED %@ %@", validity[@"code"], validity[@"message"]);
}
return YES;
}
И я реализовал методы NSURLConnectionDelegate следующим образом:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSLog(@"API LINK %@", challenge.protectionSpace.host);
if ([challenge.protectionSpace.host isEqualToString:SPAtajosApiLink])
{
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
Тем не менее, мое приложение всегда вылетает со следующим сообщением:
2013-10-15 22: 48: 55.382 Атаджос [733: 60b] {URL:
https://MY_API_URL/www/?token=657fd6c02b3ba439e69b060f7f7680cc&object=User&action=check_authorized
} 2013-10-15 22: 48: 58.045 Atajos [733: 3b17] Ошибка загрузки HTTP NSURLConnection/CFURLConnection (kCFStreamErrorDomainSSL, -9813) 2013-10-15 22: 48: 58.049 Atajos [733: 60b] * Завершение работы приложения из-за неперехваченное исключение 'NSInvalidArgumentException', причина: 'параметр данных равен нулю' * Первый стек бросить вызов: (0x2ec2de8b 0x38f286c7 0x2ec2ddcd 0x2f5b5d77 0x5df9d 0x62395 0x31433025 0x3141e631 0x313b8be7 0x313b7edd 0x3141dca1 0x3389976d 0x33899357 0x2ebf877f 0x2ebf871b 0x2ebf6ee7 0x2eb61541 0x2eb61323 0x3141cf43 0x314181e5 0x62191 0x39421ab7) LibC++abi.dylib: завершается с неисследованным исключением типа NSException
Итак, NSData, предположительно, параметр в NSJSONSerialization равен NULL. Вопрос, почему?
Как ни странно, у меня есть похожий код, который на самом деле работает с UIWebView, взаимодействующим с веб-сайтом по ненадежному SSL:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//Need to rebuild base URL. Otherwise I get the parameters which will always fail the check.
NSURL *requestUrl = [request URL];
NSString *basicPathString = [NSString stringWithFormat:@"%@://%@:%@%@", requestUrl.scheme, requestUrl.host, requestUrl.port, requestUrl.path];
NSLog(@"%@", basicPathString);
if([basicPathString isEqualToString:SPAtajosLoginLink])
{
__block NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:request.URL.absoluteURL]
options:NSJSONReadingMutableContainers
error:nil];
NSLog(@"Auth token is %@", jsonResponse[@"token"]);
[self dismissViewControllerAnimated:YES completion:^{
if([jsonResponse[@"code"] isEqualToNumber:[NSNumber numberWithInt:200]])
{
[[PDKeychainBindings sharedKeychainBindings] setObject:jsonResponse[@"token"]
forKey:@"com.shortcutpublicity.ios.atajos.userAccessToken"];
}else
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Se Pudo Autenticar", @"Error 500 title")
message:NSLocalizedString(@"Se ha producido un error interno del servidor (500). Por favor, trata de nuevo más tarde.", @"Error describing error 500")
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Aceptar", @"Accept") otherButtonTitles:nil];
[alertView show];
}
}];
}else {
//--------------THIS IS THE RELEVANT PART------------
BOOL result = _Authenticated;
if (!_Authenticated)
{
_FailedRequest = request;
NSURLConnection *trash = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(trash)
{
NSLog(@"Allocated succesfully.");
}
}
return result;
}
return YES;
}
-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSURL* baseURL = [NSURL URLWithString:SPatajosAuthLink];
if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
NSLog(@"trusting connection to host %@", challenge.protectionSpace.host);
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
} else
NSLog(@"Not trusting connection to host %@", challenge.protectionSpace.host);
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)pResponse {
_Authenticated = YES;
[connection cancel];
[_webView loadRequest:_FailedRequest];
}
Я пытался адаптировать этот код, который работает с WebView, но мне не повезло, что я приспособился использовать его с NSURLConnection.
Если честно, я не совсем уверен, что знаю, как работают эти обходные пути. Я воровал и пытался адаптировать чужой код безрезультатно. Я просмотрел документы NSURLConnection и NSURLRequest и не смог решить эти проблемы. Пожалуйста, помогите мне.
2 ответа
Мы используем эту категорию в блоке #ifedf для тестирования... убедитесь, что вы НЕ оставляете это в работе:
#ifdef DEBUG
@interface NSURLRequest (IgnoreSSL)
+(BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
@end
@implementation NSURLRequest (IgnoreSSL)
+(BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host {return YES;}
@end
#endif
try this Delegate method
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
// SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
// SecTrustEvaluate(trustRef, NULL);
//
// SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trustRef, 0);
//
// NSData *certificateData = (__bridge NSData *) SecCertificateCopyData(certRef);
// NSLog(@"Subject: %@", [[NSString alloc] initWithData:certificateData encoding:NSUTF8StringEncoding]);
// [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
SecTrustRef trust = challenge.protectionSpace.serverTrust;
NSURLCredential *cred;
cred = [NSURLCredential credentialForTrust:trust];
[challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
}