次の方法で共有


チュートリアル: ネイティブ認証を使用して iOS アプリにサインインとサインアウトを追加する

適用対象: 灰色の X 記号がある白い円。 従業員テナント 白いチェック マーク記号がある緑の円。 外部テナント (詳細情報)

このチュートリアルでは、ネイティブ認証を使用して、iOS アプリでメールのワンタイム パスコードまたはユーザー名とパスワードを使用してユーザーをサインインおよびサインアウトする方法を説明します。

このチュートリアルでは、次の操作を行います。

  • メールのワンタイム パスコードまたはユーザー名 (メール アドレス) とパスワードを使ってユーザーのサインインを行います。
  • ユーザーのサインアウト。
  • サインイン エラーを処理する

[前提条件]

ユーザーのサインイン

メールのワンタイム パスコード フローを使用してユーザーをサインインさせるには、メールをキャプチャし、ユーザーのメールを検証するためのワンタイム パスコードを含むメールを送信します。 有効なワンタイム パスコードを入力すると、アプリはユーザーをサインインさせます。

パスワード付きメール フローを使用してユーザーをサインインさせるには、メール アドレスとパスワードをキャプチャします。 ユーザー名とパスワードが有効な場合、アプリによってユーザーのサインインが行われます。

ユーザーのサインインを行うには、次の操作を行う必要があります。

  1. 「ユーザーインターフェース (UI) を作成して、以下を行う:」

    • ユーザーからメール アドレスを収集します。 入力に検証を追加して、ユーザーが有効なメール アドレスを入力していることを確認します。
    • ユーザー名 (メール アドレス) とパスワードを使ってサインインを行う場合は、パスワードを収集します。
    • 電子メール ワンタイム パスコードでサインインする場合は、ユーザーから電子メールのワンタイム パスコードを収集します。
    • メール ワンタイム パスコードでサインインした場合に、ユーザーがワンタイム パスコードを再送信できるようにするボタンを追加します。
  2. UI で、次のコード スニペットに示すように select イベントによってサインインを開始するボタンを追加します。

        @IBAction func signInPressed(_: Any) {
        guard let email = emailTextField.text else {
            resultTextView.text = "email not set"
            return
        }
    
        let parameters = MSALNativeAuthSignInParameters(username: email)
        nativeAuth.signIn(parameters: parameters, delegate: self)
    }
    

    メール ワンタイム パスコード フローを使用してユーザーをサインインさせるには、次のコード スニペットを使用します。

    nativeAuth.signIn(parameters: parameters, delegate: self)
    

    渡されたデリゲート オブジェクトのメソッドの 1 つを呼び出すことによって非同期的に応答する signIn(parameters:delegate) メソッドは、SignInStartDelegate プロトコルを実装する必要があります。 ユーザーが電子メール送信フォームで提供する電子メール アドレスを含む MSALNativeAuthSignInParameters のインスタンスを渡し、self を代理人として渡します。

    パスワード付きメール フローを使用してユーザーをサインインさせるには、次のコード スニペットを使用します。

    let parameters = MSALNativeAuthSignInParameters(username: email)
    parameters.password = password
    nativeAuth.signIn(parameters: parameters, delegate: self)
    

    signIn(parameters:delegate) メソッドでは、ユーザーが指定した電子メール アドレスとそのパスワードを含む MSALNativeAuthSignInParameters のインスタンスを、SignInStartDelegate プロトコルに準拠するデリゲート オブジェクトと共に渡します。 この例では、self を渡します。

  3. SignInStartDelegate プロトコルを実装するには、メール一時パスコード フローを使用するときに、次のコードスニペットを使用します。

    extension ViewController: SignInStartDelegate {
        func onSignInStartError(error: MSAL.SignInStartError) {
            resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")"
        }
    
        func onSignInCodeRequired(
            newState: MSAL.SignInCodeRequiredState,
            sentTo: String,
            channelTargetType: MSAL.MSALNativeAuthChannelType,
            codeLength: Int
        ) {
            resultTextView.text = "Verification code sent to \(sentTo)"
        }
    }
    

    signIn(parameters:delegate) によってデリゲート メソッドが呼び出されます。 最も一般的なシナリオでは、ユーザーのメール アドレスを検証するためのコードが送信されたことを示すために、onSignInCodeRequired(newState:sentTo:channelTargetType:codeLength) が呼び出されます。 このデリゲート メソッドには、コードが送信された場所と、コードに含まれる桁数の詳細に加えて、newState 型の SignInCodeRequiredState パラメータもあります。このパラメータにより、次の 2 つの新しいメソッドにアクセスできます。

    • submitCode(code:delegate)
    • resendCode(delegate)

    submitCode(code:delegate) を使用して、ユーザーがワンタイム パスコード フォームに指定するワンタイム パスコードを送信するには、次のコード スニペットを使用します。

    newState.submitCode(code: userSuppliedCode, delegate: self)
    

    submitCode(code:delegate) は、ワンタイム パスコードとデリゲート パラメータを受け付けます。 コードを送信した後、SignInVerifyCodeDelegate プロトコルを実装してワンタイム パスコードを検証する必要があります。

    SignInVerifyCodeDelegate プロトコルをクラスの拡張機能として実装するには、次のコード スニペットを使用します。

    extension ViewController: SignInVerifyCodeDelegate {
        func onSignInVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignInCodeRequiredState?) {
            resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
        }
    
        func onSignInCompleted(result: MSALNativeAuthUserAccountResult) {
            resultTextView.text = "Signed in successfully."
            let parameters = MSALNativeAuthGetAccessTokenParameters()
            result.getAccessToken(parameters: parameters, delegate: self)
        }
    }
    

    最も一般的なシナリオでは、ユーザーがサインインしたことを示す onSignInCompleted(result) の呼び出しを受け取ります。 結果を使用して、access token を取得できます。

    getAccessToken(parameters:delegate) は、MSALNativeAuthGetAccessTokenParameters インスタンスとデリゲート パラメーターを受け取り、CredentialsDelegate プロトコルで必要なメソッドを実装する必要があります。

    最も一般的なシナリオでは、ユーザーが onAccessTokenRetrieveCompleted(result) を取得したことを示す access token の呼び出しを受け取ります。

    extension ViewController: CredentialsDelegate {
        func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) {
            resultTextView.text = "Error retrieving access token"
        }
    
        func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult) {
            resultTextView.text = "Signed in. Access Token: \(result.accessToken)"
        }
    }
    
    
  4. SignInStartDelegate フローを使用する際に プロトコルを実装するには、次のコードスニペットを使用します。

    extension ViewController: SignInStartDelegate {
        func onSignInStartError(error: MSAL.SignInStartError) {
            resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")"
        }
    
        func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {
            // User successfully signed in
        }
    }
    

    最も一般的なシナリオでは、ユーザーがサインインしたことを示す onSignInCompleted(result) の呼び出しを受け取ります。 結果を使用して、access token を取得できます。

    getAccessToken(parameters:delegate) は、MSALNativeAuthGetAccessTokenParameters インスタンスとデリゲート パラメーターを受け取り、CredentialsDelegate プロトコルで必要なメソッドを実装する必要があります。

    最も一般的なシナリオでは、ユーザーが onAccessTokenRetrieveCompleted(result) を取得したことを示す access token の呼び出しを受け取ります。

    extension ViewController: CredentialsDelegate {
        func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) {
            resultTextView.text = "Error retrieving access token"
        }
    
        func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult) {
            resultTextView.text = "Signed in. Access Token: \(result.accessToken)"
        }
    }
    
    

サインイン エラーを処理する

サインイン中、すべてのアクションが成功するわけではありません。 たとえば、ユーザーが存在しないメール アドレスでサインインしようとしたり、無効なコードを送信したりすることがあります。

  1. signIn(parameters:delegate) メソッドのエラーを処理するには、次のコード スニペットを使用します。

    func onSignInStartError(error: MSAL.SignInStartError) {
        if error.isUserNotFound || error.isInvalidUsername {
            resultTextView.text = "Invalid username"
        } else {
            resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")"
        }
    }
    
  2. submitCode() メソッドでエラーを処理するには、次のコード スニペットを使用します:

    func onSignInVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignInCodeRequiredState?) {
        if error.isInvalidCode {
            // Inform the user that the submitted code was incorrect and ask for a new code to be supplied
            let userSuppliedCode = retrieveNewCode()
            newState?.submitCode(code: userSuppliedCode, delegate: self)
        } else {
            resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
        }
    }
    

    ユーザーが誤ったメール確認コードを入力した場合、エラー ハンドラーには SignInCodeRequiredState への参照が含まれており、それを更新されたコードの送信に使用することができます。 以前に SignInVerifyCodeDelegate プロトコルを実装した際は、onSignInVerifyCodeError(error:newState) デリゲート関数を処理したときに単にエラーを表示していました。

ID トークン要求を読み取る

アプリが ID トークンを獲得したら、現在のアカウントに関連付けられている要求を取得できます。 これを行うには、次のコード スニペットを使用します。

func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {
   let claims = result.account.accountClaims
   let preferredUsername = claims?["preferred_username"] as? String
}

要求値へのアクセスに使用するキーは、ユーザー属性をトークン要求として追加するときに指定する名前です。

組み込みおよびカスタム属性をトークン要求として追加する方法については、「トークン要求にユーザー属性を追加する」記事を参照してください。

ユーザーをサインアウトする

ユーザーをサインアウトさせるには、MSALNativeAuthUserAccountResult コールバックで受け取った onSignInCompleted への参照を使用するか、getNativeAuthUserAccount() を使用して、サインインしているアカウントをキャッシュから取得し、accountResult メンバー変数に参照を格納します。

  1. こちらの説明に従って、プロジェクトのキーチェーン グループを構成します。

  2. ViewController クラスに新しいメンバー変数 var accountResult: MSALNativeAuthUserAccountResult? を追加します。

  3. viewDidLoad が正常に初期化された後に次の行を追加して、キャッシュされたアカウントを取得するように nativeAuth を更新します: accountResult = nativeAuth.getNativeAuthUserAccount()

  4. アカウントの結果を格納するように signInCompleted ハンドラーを更新します。

    func onSignInCompleted(result: MSALNativeAuthUserAccountResult) {
        resultTextView.text = "Signed in successfully"
    
        accountResult = result
    }
    
  5. サインアウト ボタンを追加し、次のコードを使用してユーザーをサインアウトさせます。

    @IBAction func signOutPressed(_: Any) {
        guard let accountResult = accountResult else {
            print("Not currently signed in")
            return
        }
    
        accountResult.signOut()
    
        self.accountResult = nil
    
        resultTextView.text = "Signed out"
    }
    

アプリでユーザーをサインアウトさせるために必要なすべての手順を正常に完了しました。 アプリケーションをビルドして実行します。 問題がなければ、サインアウト ボタンを選択して正常にサインアウトできます。

カスタム クレーム プロバイダーの構成

外部システムからのクレームをアプリに発行されるトークンに追加する場合は、カスタム クレーム プロバイダーを使用します。 カスタム クレーム プロバイダーは、外部システムからクレームを取り込むために、外部 REST API を呼び出すカスタム認証拡張機能で構成されています。

カスタム クレーム プロバイダーの構成の手順に従って、外部システムからのクレームをセキュリティ トークンに追加します。