Swift 3 URLSession与URLCredential无法正常工作

时间:2016-11-07 16:06:59

标签: ios swift swift3

我正在做URLSession,但URL需要凭据。

我在这里尝试使用URLCredentials尝试URLSession的整个方法:

func loginUser(_ username: String, password: String, completion: @escaping (_ result: Bool) -> Void)
    {
        //Create request URL as String

        let requestString = String(format:"%@", webservice) as String

        //Covert URL request string to URL

        guard let url = URL(string: requestString) else {
            print("Error: cannot create URL")
            return
        }

        //Convert URL to URLRequest

        let urlRequest = URLRequest(url: url)

        print(urlRequest)

        //Add the username and password to URLCredential

        credential = URLCredential(user:username, password:password, persistence: .forSession)

        //Setup the URLSessionConfiguration

        let config = URLSessionConfiguration.default

        //Setup the URLSession

        let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

        //Prepare the task to get data.

        let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in

            DispatchQueue.main.async(execute: {

                if(error == nil)
                {
                    completion(true)
                }
                else
                {
                    completion(false)
                }

            })

        })

        //Run the task to get data.

        task.resume()

    }

这是我的URLSessionDelegate方法:

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

        if challenge.previousFailureCount > 0
        {
            completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
        }
        else
        {
            completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
        }

    }

    /**
     Requests credentials from the delegate in response to an authentication request from the remote server.
     */

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

        completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential,credential)

    }

当我在这个委托方法中调试它时,我注意到了:

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

        if challenge.previousFailureCount > 0
        {
            completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
        }
        else
        {
            completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
        }

    }

这个方法被调用两次,当它第二次到达这一行时:

completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))

我收到此错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

然后我的应用程序崩溃了!如何解决此错误?

3 个答案:

答案 0 :(得分:4)

当你试图强行打开它时,崩溃是由于challenge.protectionSpace.serverTrust为零。

你应该解开serverTrust并将其处理为零。我的猜测是,当serverTrust为零时,challenge.error有一个值。

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

    if challenge.previousFailureCount > 0 {
        completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
    } else if let serverTrust = challenge.protectionSpace.serverTrust {
        completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
    } else {
        print("unknown state. error: \(challenge.error)")
        // do something w/ completionHandler here
    }
}

答案 1 :(得分:1)

这是swift 3的语法。

首先验证它输入的委托方法的哪个部分

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

    var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling

    var credential:URLCredential?

    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)

        if (credential != nil) {
            disposition = URLSession.AuthChallengeDisposition.useCredential
        }
        else{
            disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
        }
    }
    else{
        disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
    }

    if (completionHandler != nil) {
        completionHandler(disposition, credential);
    }
}

答案 2 :(得分:0)

这里是上述答案的略微重构,委托类检查失败的数量,使用默认值,除非质询是服务器信任类型,然后使用信任凭证调用完成:

class AuthSessionDelegate: NSObject, URLSessionDelegate {

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

    let authMethod = challenge.protectionSpace.authenticationMethod

    guard challenge.previousFailureCount < 1, authMethod == NSURLAuthenticationMethodServerTrust,
        let trust = challenge.protectionSpace.serverTrust else {
        completionHandler(.performDefaultHandling, nil)
        return
    }

    completionHandler(.useCredential, URLCredential(trust: trust))
}

}