简体   繁体   English

带有URLCredential的Swift 3 URLSession不起作用

[英]Swift 3 URLSession with URLCredential not working

I am doing a URLSession, but the URL requires credentials. 我正在执行URLSession,但是URL需要凭据。

I have this whole method here that is trying to do a URLSession with URLCredentials: 我这里有整个方法,试图用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()

    }

and here are my URLSessionDelegate Methods: 这是我的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)

    }

I notice when I debug this in this delegate method: 我注意到在此委托方法中调试此代码时:

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

    }

That this method gets called twice and when it hits this line for the second time: 该方法被调用两次,并且第二次到达该行时:

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

I get this error: 我收到此错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

and then my app crashes! 然后我的应用崩溃了! How do I fix this error? 如何解决此错误?

the crash is due to challenge.protectionSpace.serverTrust being nil when you attempt to force unwrap it. 崩溃是由于在您尝试强行打开包装时, challenge.protectionSpace.serverTrust为零。

you should unwrap serverTrust and handle it being nil. 您应该解开serverTrust并将其处理为nil。 my guess is that when serverTrust is nil challenge.error has a value. 我的猜测是,当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
    }
}

Here is syntax as per swift 3. 这是每个Swift 3的语法。

Just verify firstly in which part of the delegate method it entered 只需首先验证它在委托方法的哪一部分输入

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

Here is a slightly refactored from the above answers, a delegate class checks the number of failures, uses default unless the challenge is of type server trust it then calls the completion with trust credential: 这是从上面的答案中略微重构而成的,委托类检查失败的数量,使用默认值,除非质询是服务器信任类型,然后使用信任凭证调用完成:

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

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM