チュートリアル: iOS (Swift) モバイル アプリでユーザーをサインインさせる
これは、Microsoft Entra 外部 ID を使用してユーザーをサインインさせる方法を説明するチュートリアル シリーズの 3 番目のチュートリアルです。
このチュートリアルでは、次のことについて説明します。
- ユーザーをサインインさせる。
- ユーザーをサインアウトさせる。
前提条件
ユーザーのサインイン
iOS 用 Microsoft 認証ライブラリ (MSAL) を使用してユーザーをサインインさせるための主なオプションとしては、対話形式またはサイレント モードでのトークンの取得の 2 つがあります。
対話形式でユーザーをサインインさせるには、次のコードを使用します。
acquireTokenInteractively() { guard let applicationContext = self.applicationContext else { return } guard let webViewParameters = self.webViewParamaters else { return } updateLogging(text: "Acquiring token interactively...") let parameters = MSALInteractiveTokenParameters(scopes: Configuration.kScopes, webviewParameters: webViewParameters) parameters.promptType = .selectAccount applicationContext.acquireToken(with: parameters) { (result, error) in if let error = error { self.updateLogging(text: "Could not acquire token: \(error)") return } guard let result = result else { self.updateLogging(text: "Could not acquire token: No result returned") return } self.accessToken = result.accessToken self.updateLogging(text: "Access token is \(self.accessToken)") self.updateCurrentAccount(account: result.account) } }
このコードはまず、アプリケーション コンテキストと Web ビューのパラメーターが使用可能かどうかを確認します。 その後、ログを更新して、トークンを対話形式で取得していることを示します。 次に、対話型トークン取得用のパラメーターを設定し、スコープと Web ビューのパラメーターを指定します。 また、アカウントを選択するためのプロンプトの種類も設定します。
その後、定義されたパラメーターを使用して、アプリケーション コンテキストで
acquireToken
メソッドを呼び出します。 完了ハンドラーでは、エラーがチェックされます。 エラーが発生した場合は、エラー メッセージでログを更新します。 成功した場合は、結果からアクセス トークンを取得し、トークンを使用してログを更新し、現在のアカウントを更新します。アプリがアクセス トークンを獲得したら、現在のアカウントに関連付けられているクレームを取得できます。 これを行うには、次のコード スニペットを使用します。
let claims = result.account.accountClaims let preferredUsername = claims?["preferred_username"] as? String
このコードは、
result.account
オブジェクトのaccountClaims
プロパティにアクセスして、アカウントからクレームを読み取ります。 次に、クレーム ディクショナリから "preferred_username" クレームの値を取得し、それをpreferredUsername
変数に割り当てます。サイレント モードでユーザーをサインインさせるには、次のコードを使用します。
func acquireTokenSilently() { self.loadCurrentAccount { (account) in guard let currentAccount = account else { self.updateLogging(text: "No token found, try to acquire a token interactively first") return } self.acquireTokenSilently(currentAccount) } }
このコードは、サイレント モードでトークンを取得するプロセスを開始します。 最初に、現在のアカウントの読み込みを試みます。 現在のアカウントが見つかった場合は、そのアカウントを使用してサイレント モードでトークンの取得を続行します。 現在のアカウントが見つからなかった場合は、ログを更新してトークンが見つからないことを示し、最初に対話形式でトークンの取得を試行することを提案します。
上記のコードでは、
loadCurrentAccount
とacquireTokenSilently
の 2 つの関数を呼び出しています。loadCurrentAccount
関数には次のコードが必要です。func loadCurrentAccount(completion: AccountCompletion? = nil) { guard let applicationContext = self.applicationContext else { return } let msalParameters = MSALParameters() msalParameters.completionBlockQueue = DispatchQueue.main // Note that this sample showcases an app that signs in a single account at a time applicationContext.getCurrentAccount(with: msalParameters, completionBlock: { (currentAccount, previousAccount, error) in if let error = error { self.updateLogging(text: "Couldn't query current account with error: \(error)") return } if let currentAccount = currentAccount { self.updateCurrentAccount(account: currentAccount) self.acquireTokenSilently(currentAccount) if let completion = completion { completion(self.currentAccount) } return } // If testing with Microsoft's shared device mode, see the account that has been signed out from another app. More details here: // https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-ios-shared-devices if let previousAccount = previousAccount { self.updateLogging(text: "The account with username \(String(describing: previousAccount.username)) has been signed out.") } else { self.updateLogging(text: "") } self.accessToken = "" self.updateCurrentAccount(account: nil) if let completion = completion { completion(nil) } }) }
このコードは、iOS 用 MSAL を使用して現在のアカウントを読み込みます。 エラーをチェックし、それに応じてログを更新します。 現在のアカウントが見つかった場合は、それを更新し、サイレント モードでトークンの取得を試みます。 以前のアカウントが存在する場合は、サインアウトをログに記録します。アカウントが見つからなかった場合は、アクセス トークンをクリアします。 最後に、指定されている場合は完了ブロックを実行します。
acquireTokenSilently
関数には次のコードが含まれている必要があります。func acquireTokenSilently(_ account : MSALAccount) { guard let applicationContext = self.applicationContext else { return } /** Acquire a token for an existing account silently - forScopes: Permissions you want included in the access token received in the result in the completionBlock. Not all scopes are guaranteed to be included in the access token returned. - account: An account object that we retrieved from the application object before that the authentication flow will be locked down to. - completionBlock: The completion block that will be called when the authentication flow completes, or encounters an error. */ updateLogging(text: "Acquiring token silently...") let parameters = MSALSilentTokenParameters(scopes: Configuration.kScopes, account: account) applicationContext.acquireTokenSilent(with: parameters) { (result, error) in if let error = error { let nsError = error as NSError // interactionRequired means we need to ask the user to sign-in. This usually happens // when the user's Refresh Token is expired or if the user has changed their password // among other possible reasons. if (nsError.domain == MSALErrorDomain) { if (nsError.code == MSALError.interactionRequired.rawValue) { DispatchQueue.main.async { self.acquireTokenInteractively() } return } } self.updateLogging(text: "Could not acquire token silently: \(error)") return } guard let result = result else { self.updateLogging(text: "Could not acquire token: No result returned") return } self.accessToken = result.accessToken self.updateLogging(text: "Refreshed Access token is \(self.accessToken)") self.updateSignOutButton(enabled: true) } }
この関数は、iOS 用 MSAL を使用して、既存のアカウントのトークンをサイレント モードで取得します。
applicationContext
を検証した後、トークンの取得プロセスをログに記録します。MSALSilentTokenParameters
を使用して、必要なパラメーターを定義します。 次に、サイレント モードでトークンの取得を試みます。 エラーが発生した場合は、ユーザーによる対話型操作の要件をチェックし、必要に応じて対話型プロセスを開始します。 成功した場合は、accessToken
プロパティを更新し、更新されたトークンをログに記録し、サインアウト ボタンを有効にして終了します。
ユーザーをサインアウトする
iOS 用 MSAL を使用して iOS (Swift) アプリからユーザーをサインアウトさせるには、次のコードを使用します。
@IBAction func signOut(_ sender: UIButton) {
guard let applicationContext = self.applicationContext else { return }
guard let account = self.currentAccount else { return }
guard let webViewParamaters = self.webViewParamaters else { return }
updateLogging(text: "Signing out...")
do {
/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/
let signoutParameters = MSALSignoutParameters(webviewParameters: webViewParamaters)
// If testing with Microsoft's shared device mode, trigger signout from browser. More details here:
// https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-ios-shared-devices
if (self.currentDeviceMode == .shared) {
signoutParameters.signoutFromBrowser = true
} else {
signoutParameters.signoutFromBrowser = false
}
applicationContext.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in
if let error = error {
self.updateLogging(text: "Couldn't sign out account with error: \(error)")
return
}
self.updateLogging(text: "Sign out completed successfully")
self.accessToken = ""
self.updateCurrentAccount(account: nil)
})
}
}
このコードは、applicationContext
、currentAccount
、および webViewParamaters
の存在を検証します。 次に、サインアウト プロセスをログに記録します。 このコードは、指定されたアカウントのキャッシュからすべてのトークンを削除します。 現在のデバイス モードに応じて、ブラウザーからサインアウトするかどうかを決定します。 完了すると、それに応じてログ テキストを更新します。 サインアウト プロセス中にエラーが発生した場合は、エラー メッセージをログに記録します。 サインアウトに成功すると、アクセス トークンを空の文字列に更新し、現在のアカウントをクリアします。