Swift: Как запросить URL с самозаверяющим сертификатом?

Я открываю соединение SSL для получения JSON в Swift, но я тестирую на своем собственном сервере с самозаверяющим сертификатом. Вот фрагмент запроса URL:

var urlPath = "https://myhost.com/get_json"
var url: NSURL = NSURL(string: urlPath)
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)        
connection.start()

Однако, это отклонено (правильно) из-за сертификата:

Opening connection to https://myhost.com/get_json
2014-06-05 09:37:02.543 AppName[44835:3182593] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Connection failed.The certificate for this server is invalid. You might be connecting to a server that is pretending to be “myhost.com” which could put your confidential information at risk.## Heading ##

3 ответа

Решение

Вам понадобятся эти дополнительные методы от NSURLConnectionDelegate:

func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace?) -> Bool
{
    return protectionSpace?.authenticationMethod == NSURLAuthenticationMethodServerTrust
}

func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge?)
{
    if challenge?.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
    {
        if challenge?.protectionSpace.host == "www.myhost.com"
        {
            let credentials = NSURLCredential(forTrust: challenge!.protectionSpace.serverTrust)
            challenge!.sender.useCredential(credentials, forAuthenticationChallenge: challenge)
        }
    }

    challenge?.sender.continueWithoutCredentialForAuthenticationChallenge(challenge)
}

ПРИМЕЧАНИЕ. Это возможно только при использовании асинхронного NSURLConnection,

Это мое решение для Swift3

let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue.main)


extension WebServiceManager : URLSessionDelegate {
    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

        var trustedHostArray = [String]()

        if Utils.getEnviroment() == Constants.Environment.Production.rawValue {
            trustedHostArray = Constants.TRUSTED_HOSTS.Production
        } else {
            trustedHostArray = Constants.TRUSTED_HOSTS.Develop
        }

        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            if trustedHostArray.contains(challenge.protectionSpace.host) {
                let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
                challenge.sender?.use(credential, for: challenge)
                completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential)
            }
        }
    }
}

Я обновил ответ Эрика для Swift 3:

func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: URLProtectionSpace?) -> Bool {
    return protectionSpace?.authenticationMethod == NSURLAuthenticationMethodServerTrust
}

func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: URLAuthenticationChallenge?) {
    if challenge?.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
    {
        if challenge?.protectionSpace.host == "www.myhost.com"
        {
            let credentials = URLCredential(trust: challenge!.protectionSpace.serverTrust!)
            challenge!.sender?.use(credentials, for: challenge!)
        }
    }

    challenge?.sender?.continueWithoutCredential(for: challenge!)
}
Другие вопросы по тегам