【问题标题】:Swift 3 URLSession with URLCredential not working带有 URLCredential 的 Swift 3 URLSession 不起作用
【发布时间】:2017-03-21 01:16:46
【问题描述】:

我正在执行 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

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

【问题讨论】:

    标签: ios swift swift3


    【解决方案1】:

    崩溃是由于当您尝试强制解包时 challenge.protectionSpace.serverTrust 为 nil。

    你应该解开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
        }
    }
    

    【讨论】:

    • 应用程序不再崩溃,但是当我尝试运行登录方法时,无论我输入的凭据(对或错)它都直接进入这一行print("unknown state. error: \(challenge.error)")
    • 调试后会跳转到completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))这一行,然后以某种方式再次运行这个方法,然后跳转到这一行:print("unknown state. error: \(challenge.error)")
    • 您确定打印语句中没有错字吗? \(challenge.error) 应替换为实际的错误对象
    【解决方案2】:

    这里是按照 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);
        }
    }
    

    【讨论】:

    • 这里有两个问题...首先,当我运行 loginUser 方法时,它会运行 urlSession 方法两次,第一次转到 disposition = URLSession.AuthChallengeDisposition.useCredential,然后第二次转到 disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
    • 这行if (completionHandler != nil) {也给了我一个警告Comparing non-optional value of type '(URLSession.AuthChallengeDisposition, URLCredential?) -> Void' to nil always returns true
    • 您是否尝试第二次打印authenticationMethod 值。
    【解决方案3】:

    这是对上述答案的轻微重构,委托类检查失败次数,使用默认值,除非挑战是服务器信任类型,然后使用信任凭据调用完成:

    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))
    }
    

    }

    【讨论】:

      猜你喜欢
      • 2017-09-06
      • 1970-01-01
      • 1970-01-01
      • 2017-04-05
      • 1970-01-01
      • 2019-04-11
      • 2021-12-04
      • 2017-06-22
      • 2016-12-23
      相关资源
      最近更新 更多