WKWebViewにBasic認証を正しく実装する
WKWebViewにBasic認証を実装するサンプルコードです。
- 環境
- Xcode10.1
最終的なサンプルを見たいならこちら
WebViewの生成
WKWebViewを生成しdelegateの設定を行います。
認証に関するdelegateは navigationDelegate
です。(WKWebViewには uiDelegate
もあるので気をつけて。)
以下はコードで生成する例です(Storyboardでも問題なし)。
ViewController.swift
import UIKit
import WebKit
class ViewController: UIViewController {
var webView: WKWebView!
override func loadView() {
view = UIView(frame: .zero)
let configuration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: configuration)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
view.addSubview(webView)
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.leftAnchor.constraint(equalTo: view.leftAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
webView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
}
}
extension ViewController: WKNavigationDelegate {
}
認証のdelegateを実装
認証に関するdelegateメソッドを実装します。
まずは何もしないメソッドを書きます。
ViewController.swift
extension ViewController: WKNavigationDelegate {
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch challenge.protectionSpace.authenticationMethod {
default:
completionHandler(.performDefaultHandling, nil)
}
}
}
Basic認証の処理を実装
認証に関するdelegateメソッドは、Basic認証に限らず他の認証でも呼ばれます。
Basic認証の場合の処理と、それ以外の処理を分けて実装します。
URLCredentialにIDとPasswordを設定して、completionHandlerを呼び出します。
ViewController.swift
extension ViewController: WKNavigationDelegate {
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch challenge.protectionSpace.authenticationMethod {
case NSURLAuthenticationMethodHTTPBasic:
let credential = URLCredential(user: "user", password: "password", persistence: URLCredential.Persistence.forSession)
completionHandler(.useCredential, credential)
default:
completionHandler(.performDefaultHandling, nil)
}
}
}
サンプル
UIAlertControllerでユーザー人入力を求める場合の最終的なコードは以下になります。
IDとPasswordを入力したとき、キャンセルしたとき、そのそれぞれでcompletionHandlerを呼び出します。
ViewController.swift
import UIKit
import WebKit
class ViewController: UIViewController {
var webView: WKWebView!
override func loadView() {
view = UIView(frame: .zero)
let configuration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: configuration)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
view.addSubview(webView)
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.leftAnchor.constraint(equalTo: view.leftAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
webView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
}
override func viewDidLoad() {
let request = URLRequest(url: URL(string: "https://hogehoge.com/")!)
webView.load(request)
}
}
extension ViewController: WKNavigationDelegate {
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch challenge.protectionSpace.authenticationMethod {
case NSURLAuthenticationMethodHTTPBasic:
let alert = UIAlertController(title: "Basic認証", message: "ユーザ名とパスワードを入力してください", preferredStyle: .alert)
alert.addTextField {
$0.placeholder = "user"
}
alert.addTextField {
$0.placeholder = "password"
$0.isSecureTextEntry = true
}
let login = UIAlertAction(title: "ログイン", style: .default) { (_) in
guard
let user = alert.textFields?[0].text,
let password = alert.textFields?[1].text
else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let credential = URLCredential(user: user, password: password, persistence: URLCredential.Persistence.forSession)
completionHandler(.useCredential, credential)
}
let cancel = UIAlertAction(title: "キャンセル", style: .cancel) { (_) in
completionHandler(.cancelAuthenticationChallenge, nil)
}
alert.addAction(login)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
default:
completionHandler(.performDefaultHandling, nil)
}
}
}