Аутентификация с помощью WKWebView в Swift

В моем приложении iOS я хотел бы использовать WKWebView для переноса внешнего URL-адреса в приложение. Для этого URL требуется базовая аутентификация (для этого необходимы учетные данные пользователя и пароля, как на следующем снимке экрана).

введите описание изображения здесь

После некоторого расследования я пытаюсь использовать метод didReceiveAuthenticationChallenge, чтобы включить автоматический вход в систему, поэтому я не понимаю, как это работает.

Это мой код.

import UIKit
import WebKit

class WebViewController: UIViewController, WKNavigationDelegate {

    var webView: WKWebView?

    private var request : NSURLRequest {
        let baseUrl = "https://unimol.esse3.cineca.it/auth/Logon.do"
        let URL = NSURL(string: baseUrl)!
        return NSURLRequest(URL: URL)
    }

    /* Start the network activity indicator when the web view is loading */
    func webView(webView: WKWebView,
                 didStartProvisionalNavigation navigation: WKNavigation){
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    }

    /* Stop the network activity indicator when the loading finishes */
    func webView(webView: WKWebView,
                 didFinishNavigation navigation: WKNavigation){
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    }

    func webView(webView: WKWebView,
                 decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse,
                                                   decisionHandler: ((WKNavigationResponsePolicy) -> Void)){
        decisionHandler(.Allow)
    }

    func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {

        if challenge.protectionSpace.host == "https://unimol.esse3.cineca.it/auth/Logon.do" {
            let user = "*******"
            let password = "******"
            let credential = NSURLCredential(user: user, password: password, persistence: NSURLCredentialPersistence.ForSession)
            challenge.sender?.useCredential(credential, forAuthenticationChallenge: challenge)
        }
    }

    override func viewDidLoad() {
        /* Create our preferences on how the web page should be loaded */
        let preferences = WKPreferences()
        preferences.javaScriptEnabled = false

        /* Create a configuration for our preferences */
        let configuration = WKWebViewConfiguration()
        configuration.preferences = preferences

        /* Now instantiate the web view */
        webView = WKWebView(frame: view.bounds, configuration: configuration)

        if let theWebView = webView {
            /* Load a web page into our web view */
            let urlRequest = self.request
            theWebView.loadRequest(urlRequest)
            theWebView.navigationDelegate = self
            view.addSubview(theWebView)
        }
    }
}

Я столкнулся с этим исключением:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Completion handler passed to -[MyUnimol.WebViewController webView:didReceiveAuthenticationChallenge:completionHandler:] was not called'

Если я удалю метод didReceiveAuthenticationChallenge, я могу достигнуть URL-адреса, но, к сожалению, неверные учетные данные.

Кто-нибудь может объяснить мне, что я делаю неправильно?

Ответ 1

Добавьте следующую строку:

completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)

в конце didReceiveAuthenticationChallenge решил проблему.

Ответ 2

Я опоздал на вечеринку, но все же это может быть полезно для кого-то.

Чтобы поддержать проверку подлинности в WKWebview Swift 4, заполните код, как показано ниже

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        guard let hostname = webView.url?.host else {
            return
        }

        let authenticationMethod = challenge.protectionSpace.authenticationMethod
        if authenticationMethod == NSURLAuthenticationMethodDefault || authenticationMethod == NSURLAuthenticationMethodHTTPBasic || authenticationMethod == NSURLAuthenticationMethodHTTPDigest {
            let av = UIAlertController(title: webView.title, message: String(format: "AUTH_CHALLENGE_REQUIRE_PASSWORD".localized, hostname), preferredStyle: .alert)
            av.addTextField(configurationHandler: { (textField) in
                textField.placeholder = "USER_ID".localized
            })
            av.addTextField(configurationHandler: { (textField) in
                textField.placeholder = "PASSWORD".localized
                textField.isSecureTextEntry = true
            })

            av.addAction(UIAlertAction(title: "BUTTON_OK".localized, style: .default, handler: { (action) in
                guard let userId = av.textFields?.first?.text else{
                    return
                }
                guard let password = av.textFields?.last?.text else {
                    return
                }
                let credential = URLCredential(user: userId, password: password, persistence: .none)
                completionHandler(.useCredential,credential)
            }))
            av.addAction(UIAlertAction(title: "BUTTON_CANCEL".localized, style: .cancel, handler: { _ in
                completionHandler(.cancelAuthenticationChallenge, nil);
            }))
            self.parentViewController?.present(av, animated: true, completion: nil)
        }else if authenticationMethod == NSURLAuthenticationMethodServerTrust{
            // needs this handling on iOS 9
            completionHandler(.performDefaultHandling, nil);
        }else{
            completionHandler(.cancelAuthenticationChallenge, nil);
        }
    }