WKWebViewでBasic認証を行う

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

目次

全体的な流れ

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

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

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

認証に対応するために必要な処理を何も実装せずに、認証が必要なページにアクセスすると、エラーページが表示されます。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を実行します。

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

著書紹介

Authored Books

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

目次