WKWebViewでBasic認証を行う

WKWebViewで認証されたページにアクセスしたいときは、確認証方法に合わせた処理が必要です。この記事ではHTTPのBasic認証に対応する方法を解説します。

全体的な流れ

WKWebViewでBasic認証に対応するには、次のような流れを実装します。

  1. 認証エラーになったら、認証方式を判定する。
  2. アカウント情報を持っていたら、アカウント情報をヘッダに追加してアクセスする。
  3. アカウント情報を持っていなかったら、認証画面を表示する。
  4. アカウント情報が入力されたら、アカウント情報をヘッダに追加してアクセスする。

テスト用にBasic認証を行うページを用意する方法については、以下の記事をご覧ください。

上記の記事ではDockerで開発マシンの中にBasic認証を行うページを構築する方法を解説しています。開発時のテストに使うのに手軽な方法だと思います。

認証が必要なページにアクセスするとどうなる?

認証に対応するために必要な処理を何も実装せずに、認証が必要なページにアクセスすると、エラーページが表示されます。SafariやChromeのような認証ダイアログは自動的には表示されません。

これらの処理はアプリ側で実装する必要があります。

まずは、次の2つを実装します。

  1. 認証エラーになったことを判定する。
  2. 認証方式がBasic認証かどうかを判定する。

認証エラーになったことの判定

認証エラーになり、認証が必要になると、WKNavigationDelegateの次のメソッドが呼ばれます。

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
                 completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

WKNavigationDelegateプロトコルに適合したクラスで実装し、WKWebViewクラスのnavigationDelegateプロトコルにセットします。

必要な処理を実行して、最後にcompletionHandlerを実行します。

認証方式の判定

認証方式を判定するには、URLAuthenticationChallengeprotectionSpaceプロパティを取得して、URLProtectionSpaceauthenticationMethodプロパティをチェックします。

次のコードは、Basic認証かどうかを判定しています。

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
			 completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
	var isBasicAuthentication = false
	
	let method = challenge.protectionSpace.authenticationMethod
	if method.compare(NSURLAuthenticationMethodHTTPBasic) == .orderedSame {
		isBasicAuthentication = true
	}
	
	completionHandler(.performDefaultHandling, nil)
}

Basic認証の場合は、authenticationMethodの値はNSURLAuthenticationMethodHTTPBasicになっています。

認証画面の表示

Basic認証だったら、認証画面を表示し、それ以外だったらデフォルトの処理を行うように実装します。

認証画面でログイン、または、キャンセルボタンが押されたら、webView(_:didReceive:completionHandler:)で取得したcompletionHandlerを実行します。

次のコードは、UIAlertControllerでログイン画面を作っているサンプルコードです。とりあえず、表示するというコードなので、ボタンの処理は特に行っていません。

func showBasicAuthAlert(completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
	let alert = UIAlertController(title: "Authentication",
								  message: "Enter your account",
								  preferredStyle: .alert)
	
	// ユーザー名のテキストフィールドを作成する
	alert.addTextField { (textField) in
		textField.placeholder = "User Name"
		textField.keyboardType = .asciiCapable
	}
	
	// パスワードのテキストフィールドを作成する
	alert.addTextField { (textField) in
		textField.placeholder = "Password"
		textField.keyboardType = .asciiCapable
		textField.isSecureTextEntry = true
	}
	
	// ログインボタンを作成する
	alert.addAction(UIAlertAction(title: "Login", style: .default, handler: { (action) in
		completionHandler(.performDefaultHandling, nil)
	}))
	
	// キャンセルボタンを作成する
	alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) in
		completionHandler(.performDefaultHandling, nil)
	}))
	
	// アラートを表示する
	self.present(alert, animated: true, completion: nil)
}

キャンセルボタンの処理

キャンセルボタンが押されたときの処理を実装します。とはいっても、既に実装済みのコードです。

completionHandlerの引数に.performDefaultHandlingを指定して実行します。cancelAuthenticationChallengeも定義されていて、そちらを使った方が良いと最初は思ったのですが、試してみると、cancelAuthenticationChallenageは処理の中断でした。

SafariやChromeの動作を見てみると、Basic認証でエラーになったときは、エラーページを表示するようになっています。しかし、cancelAuthenticationChallengeを指定してしまうと、エラーページの表示処理も行わずに中止してしまいました。

.performDefaultHandlingを指定すると、エラーページの表示に遷移するので、WKWebViewと組み合わせるときは、.performDefaultHandlingの方が良いと思います。

但し、エラーになったら、WKWebView自体を非表示にして、別の画面に遷移するような仕様のときは、cancelAuthenticationChallengeの方が良いでしょう。

ログイン処理

ログイン処理は、次の処理を実装します。

  1. 入力されたユーザー名とパスワードを取得する
  2. 取得したユーザー名とパスワードから認証情報を作成する
  3. 作成した認証情報を使って認証を行う

コードにすると次のようになります。

// ログインボタンを作成する
alert.addAction(UIAlertAction(title: "Login", style: .default, handler: { (action) in
	var userName = ""
	var password = ""
	
	// 入力された文字列を取得する
	if let textFields = alert.textFields {
		if let str = textFields[0].text {
			userName = str
		}
		if let str = textFields[1].text {
			password = str
		}
	}
	
	// このセッション専用の認証情報を作成する
	let credential = URLCredential(user: userName, password: password, persistence: .forSession)
	
	// 作成した認証情報で認証を行う
	completionHandler(.useCredential, credential)
}))

認証情報は、URLCredentialのインスタンスです。イニシャライザでユーザー名とパスワードを指定できます。最後のpersistenceは認証情報をどのように保持するかを指定します。

次の値が定義されています。

  • none : 保持しない
  • forSession : セッション中だけ保持する
  • permanent : キーチェインに保存する
  • synchronizable : キーチェインに保存し、Apple IDに紐付けて同期可能にする(iCloud経由で同期可能という意味だと思います)

認証情報を作成したら、useCredentialを指定して completionHandlerを実行します。

認証に成功すると、ページにアクセスできます。

投稿者プロフィール

林 晃
林 晃macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者
アールケー開発代表。macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者。ObjC/Swift/C++使い。豊富な開発実務経験を基に、教育コンテンツ開発、技術書執筆、技術指導、技術セミナー講師、企業内研修講師、行政・自治体職員研修講師も行います。

基礎から学ぶMetal


「基礎から学ぶMetal」を執筆しました。本書はMetalを使ってGPUプログラミングを行うための最初のステップを解説するMetalの解説書です。

私が初めてGPUプログラミングを行ったとき、どこから手をつけて、学んでいけば良いのか分からず呆然としました。もし、あのとき、これを教えてくれればという部分を解説しました。本書で解説している部分はMetalの基礎となる部分で、Metalを使うときに必ず触れることになる部分です。

詳細

基礎から学ぶSwiftUI


「基礎から学ぶ SwiftUI」というタイトルの本を執筆しました。

SwiftUIの入門書です。

SwiftUIのコンセプトは「ユーザーインターフェイスを作るための最短パスを提供する」「一度学べば(Appleのプラットフォームの)どこにでも適用できる」です。

SwiftUIの概要から始まって、一つ一つのテクノロジートピックに注目しながらSwiftUIとは何か?どんなことができるのか?どのようなコードを書けば良いのかなどを丸々一冊使って解説しています。

詳細

関連記事

  1. 【2020/4/1更新】【Swift|ObjC 】 UIWebView…

  2. WKWebViewとSFSafariViewControllerのどち…

  3. docker+nginx+phpの環境を作る

  4. Docker+NginxでBasic認証を行うまでの3つの手順

  5. Transmitの同時接続数の上限値を設定する

  6. NginxのPOSTの設定

  7. お問い合わせフォームのリニューアル

  8. Webサイトのリニューアル その2

最近の著書

  1. 基礎から学ぶ SwiftUI

最近の記事