在 Swift 中使用 WKWebView 进行身份验证
Authentication with WKWebView in 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 但它给了我错误的凭据。
谁能解释一下我做错了什么?
添加以下行:
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)
在 didReceiveAuthenticationChallenge
结束时解决了问题。
我参加聚会迟到了,但这仍然对某人有用。
支持WKWebview中的auth challenge 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);
}
}
更简单的方法:
虽然这个答案看起来多余,但发布可能会帮助其他天真的开发者(比如我)。
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard (webView.url?.host) != nil else {
return
}
let authenticationMethod = challenge.protectionSpace.authenticationMethod
if authenticationMethod == NSURLAuthenticationMethodDefault || authenticationMethod == NSURLAuthenticationMethodHTTPBasic || authenticationMethod == NSURLAuthenticationMethodHTTPDigest {
let credential = URLCredential(user: userName, password: password, persistence: .none)
completionHandler(.useCredential, credential)
} else if authenticationMethod == NSURLAuthenticationMethodServerTrust {
completionHandler(.performDefaultHandling, nil)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
在我的 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 但它给了我错误的凭据。
谁能解释一下我做错了什么?
添加以下行:
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)
在 didReceiveAuthenticationChallenge
结束时解决了问题。
我参加聚会迟到了,但这仍然对某人有用。
支持WKWebview中的auth challenge 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);
}
}
更简单的方法:
虽然这个答案看起来多余,但发布可能会帮助其他天真的开发者(比如我)。
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard (webView.url?.host) != nil else {
return
}
let authenticationMethod = challenge.protectionSpace.authenticationMethod
if authenticationMethod == NSURLAuthenticationMethodDefault || authenticationMethod == NSURLAuthenticationMethodHTTPBasic || authenticationMethod == NSURLAuthenticationMethodHTTPDigest {
let credential = URLCredential(user: userName, password: password, persistence: .none)
completionHandler(.useCredential, credential)
} else if authenticationMethod == NSURLAuthenticationMethodServerTrust {
completionHandler(.performDefaultHandling, nil)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}