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

適用対象: 次の内容が外部テナントに適用されることを示す白いチェック マーク記号が付いた緑の円。 外部テナント (詳細)

このチュートリアルでは、ネイティブ認証を使用して、iOS/macOS アプリで電子メール ワンタイム パスコードまたはユーザー名 (電子メール) とパスワードを使用してユーザーをサインアップする方法について説明します。 また、サインアップ時にユーザー属性 (ユーザー名 (エイリアス) を含む) を収集し、エラーを処理する方法についても説明します。

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

  • メールのワンタイム パスコードまたはメール アドレスとパスワードの組み合わせを使用してユーザーを登録します。
  • ユーザー名 (エイリアス) など、サインアップ時にユーザー属性を収集します。
  • サインアップ エラーを処理します。

[前提条件]

ユーザーをサインアップする

電子メールワンタイム パスコードまたはユーザー名 (電子メール) とパスワードを使用してユーザーをサインアップするには、ユーザーからメールを収集し、電子メールワンタイム パスコードを含む電子メールをユーザーに送信します。 ユーザーは、有効なメールのワンタイム パスコードを入力し、ユーザー名を検証します。

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

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

    • ユーザーからメール アドレスを収集します。 ユーザーが有効なメール アドレスを入力していることを確認するために、入力に検証を追加します。
    • ユーザー名 (メール アドレス) とパスワードでサインアップした場合、パスワードを収集します。
    • アプリでエイリアス ベースのサインインがサポートされている場合は、ユーザー名 (エイリアス) を収集します。
    • ユーザーからメールのワンタイム パスコードを収集します。
    • 必要に応じて、ユーザー属性を収集します。
    • ユーザーがコードを受信しなかった場合にワンタイム パスコードを再送信します。
    • サインアップ フローを開始します。
  2. アプリで、select イベントによって次のコード スニペットをトリガーするボタンを追加します。

    @IBAction func signUpPressed(_: Any) {
        guard let email = emailTextField.text else {
            resultTextView.text = "Email or password not set"
            return
        }
    
        let parameters = MSALNativeAuthSignUpParameters(username: email)
        nativeAuth.signUp(parameters: parameters, delegate: self)
    }
    
    • 電子メール ワンタイム パスコードを使用してユーザーをサインアップするには、ライブラリの signUp(parameters:delegate) メソッドを使用します。このメソッドは、渡されたデリゲート オブジェクトでメソッドの 1 つを呼び出すことによって非同期的に応答します。このメソッドは、SignUpStartDelegate プロトコルを実装する必要があります。 次のコード行は、ユーザーのサインアップ プロセスを開始します。

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

      signUp(parameters:delegate) メソッドで、送信フォームからユーザーの電子メール アドレスを含むMSALNativeAuthSignUpParameters インスタンスをデリゲート (SignUpStartDelegate プロトコルを実装するクラス) と共に渡します。

    • メール アドレスとパスワードの組み合わせを使用してユーザーをサインアップさせるには、次のコード スニペットを使用します。

      @IBAction func signUpPressed(_: Any) {
          guard let email = emailTextField.text, let password = passwordTextField.text else {
             resultTextView.text = "Email or password not set"
             return
          }
      
          let parameters = MSALNativeAuthSignUpParameters(username: email)
          parameters.password = password
          nativeAuth.signUp(parameters: parameters, delegate: self)
      }
      

      ライブラリの signUp(parameters:delegate) メソッドは、渡されたデリゲート オブジェクトのメソッドのいずれかを呼び出すことによって非同期的に応答します。このメソッドは、 SignUpStartDelegate プロトコルを実装する必要があります。 次のコード行は、ユーザーのサインアップ プロセスを開始します。

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

      signUp(parameters:delegate) メソッドで、ユーザーの電子メール アドレスとそのパスワードを含むMSALNativeAuthSignUpParameters インスタンスをデリゲート (SignUpStartDelegate プロトコルを実装するクラス) と共に渡します。

    • クラスの拡張機能として SignUpStartDelegate プロトコルを実装するには、次のコマンドを使用します。

      extension ViewController: SignUpStartDelegate {
          func onSignUpStartError(error: MSAL.SignUpStartError) {
              resultTextView.text = "Error signing up: \(error.errorDescription ?? "no description")"
          }
      
          func onSignUpCodeRequired(
              newState: MSAL.SignUpCodeRequiredState,
              sentTo: String,
              channelTargetType: MSAL.MSALNativeAuthChannelType,
              codeLength: Int
          ) {
              resultTextView.text = "Verification code sent to \(sentTo)"
          }
      }
      

      signUp(parameters:delegate) を呼び出すと、onSignUpCodeRequired() または onSignUpStartError() のデリゲート メソッドが呼び出されます。 ユーザーのメール アドレスを確認するコードが送信されたことを示すために、onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength) が呼び出されます。 コードが送信された場所と、コードに含まれる桁数の詳細に加えて、このデリゲート メソッドには、newState型のSignUpCodeRequiredState パラメーターもあります。これにより、2 つの新しいメソッドにアクセスできます。

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

      ユーザーが指定したコードを送信するには、次のコードを使用します。

      newState.submitCode(code: userSuppliedCode, delegate: self)
      
      • クラスの拡張機能として SignUpVerifyCodeDelegate プロトコルを実装するには、次のコマンドを使用します。

        extension ViewController: SignUpVerifyCodeDelegate {
            func onSignUpVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignUpCodeRequiredState?) {
                resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
            }
        
            func onSignUpCompleted(newState: SignInAfterSignUpState) {
                resultTextView.text = "Signed up successfully!"
            }
        }
        

        submitCode(code:delegate)はデリゲート パラメーターを受け取り、SignUpVerifyCodeDelegate プロトコルで必要なメソッドを実装する必要があります。 最も一般的なシナリオでは、ユーザーがサインアップされ、フローが完了したことを示す onSignUpCompleted(newState) の呼び出しを受け取ります。

サインアップ中にユーザー属性を収集する

ユーザーのサインアップにメールのワンタイム パスコードを使用するか、ユーザー名 (メール アドレス) とパスワードの組み合わせを使用するかに関係なく、ユーザーのアカウントが作成される前にユーザー属性を収集できます。 signUp(parameters:delegate) メソッドは、属性プロパティを持つ MSALNativeAuthSignUpParameters を使用して呼び出すことができます。

  1. ユーザー属性を収集するには、次のコード スニペットを使用します。

    let attributes = [
        "country": "United States",
        "city": "Redmond"
    ]
    
    let parameters = MSALNativeAuthSignUpParameters(username: email)
    parameters.password = password
    parameters.attributes = attributes
    nativeAuth.signUp(parameters: parameters, delegate: self)
    

    signUp(parameters:delegate)は、onSignUpCodeRequired() メソッドまたは onSignUpStartError() デリゲート メソッドの呼び出し、またはデリゲートに実装されている場合は onSignUpAttributesInvalid(attributeNames: [String]) の呼び出しになります。

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

    extension ViewController: SignUpStartDelegate {
        func onSignUpStartError(error: MSAL.SignUpStartError) {
            resultTextView.text = "Error signing up: \(error.errorDescription ?? "no description")"
        }
    
        func onSignUpCodeRequired(
            newState: MSAL.SignUpCodeRequiredState,
            sentTo: String,
            channelTargetType: MSAL.MSALNativeAuthChannelType,
            codeLength: Int
        ) {
            resultTextView.text = "Verification code sent to \(sentTo)"
        }
    
        func onSignUpAttributesInvalid(attributeNames: [String]) {
           resultTextView.text = "Invalid attributes  \(attributeNames)"
        }
    }
    

    属性が無効の場合は、メソッド onSignUpAttributesInvalid(attributeNames: [String]) が呼び出されます。 この場合は、無効な属性の一覧をユーザーに表示します。 それ以外の場合は、ユーザーのメール アドレスを確認するコードが送信されたことを示すために、onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength) が呼び出されます。 コードの受信者やコードの桁数などの詳細とは別に、このデリゲート メソッドには newState 型のSignUpCodeRequiredState パラメーターがあり、2 つの新しいメソッドにアクセスできます。

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

1つ以上のページにわたるユーザー属性

属性を 1 つ以上のページに分散するには、顧客 ID およびアクセス管理 (CIAM) テナント構成で、異なるページに収集する属性を必須として設定します。

signUp(parameters:delegate) インスタンスに属性を渡さずにMSALNativeAuthSignUpParametersを呼び出します。 次の手順では、 newState.submitCode(code: userSuppliedCode, delegate: self) を呼び出してユーザーの電子メールを確認します。

SignUpVerifyCodeDelegate プロトコルを以前と同様にクラスの拡張機能として実装しますが、今回は、必要なメソッドに加えて、省略可能なメソッドonSignUpAttributesRequired(attributes:newState)を実装する必要があります。

extension ViewController: SignUpVerifyCodeDelegate {
    func onSignUpAttributesRequired(newState: SignUpAttributesRequiredState) {
        resultTextView.text = "Attributes required"
    }

    func onSignUpVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignUpCodeRequiredState?) {
        resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
    }

    func onSignUpCompleted(newState: SignInAfterSignUpState) {
        resultTextView.text = "Signed up successfully!"
    }
}

このデリゲート メソッドには、newState 型のSignUpAttributesRequiredState パラメーターがあり、新しいメソッドにアクセスできます。

  • submitAttributes(attributes:delegate)

ユーザーが指定した属性を送信するには、次のコード スニペットを使用します。

let attributes = [
    "country": "United States",
    "city": "Redmond"
]

newState.submitAttributes(attributes: attributes, delegate: self)

また、クラスの拡張機能として SignUpAttributesRequiredDelegate プロトコルを実装します。

extension ViewController: SignUpAttributesRequiredDelegate {
    func onSignUpAttributesRequiredError(error: AttributesRequiredError) {
        resultTextView.text = "Error submitting attributes: \(error.errorDescription ?? "no description")"
    }

    func onSignUpAttributesRequired(attributes: [MSALNativeAuthRequiredAttribute], newState: SignUpAttributesRequiredState) {
        resultTextView.text = "Attributes required"
    }

    func onSignUpAttributesInvalid(attributeNames: [String], newState: SignUpAttributesRequiredState) {
        resultTextView.text = "Attributes invalid"
    }

    func onSignUpCompleted(newState: SignInAfterSignUpState) {
        resultTextView.text = "Signed up successfully!"
    }
}

ユーザーが必要なすべての属性を指定しない場合、または属性が無効な場合は、次のデリゲート メソッドが呼び出されます。

  • onSignUpAttributesInvalid: 送信された 1 つ以上の属性が入力検証に失敗したことを示します。 このエラーには、attributeNames パラメータが含まれています。これは、入力検証に失敗した開発者によって送信されたすべての属性のリストです。
  • onSignUpAttributesRequired: ユーザー アカウントを作成するには、1 つ以上の属性の送信をサーバーが要求することを示します。 これは、テナント構成で 1 つ以上の属性が必須として設定されている場合に発生します。 この結果には、属性パラメータが含まれています。これは、API に必要なユーザー属性の詳細を示す MSALNativeAuthRequiredAttribute オブジェクトのリストです。

両方のデリゲート メソッドに新しい状態参照が含まれています。 newState パラメーターを使用して、新しい属性でsubmitAttributes(attributes:delegate)を再度呼び出します。

サインアップ時にユーザー名 (エイリアス) を収集する

ユーザー名 (エイリアス) は特殊なユーザー属性です。 市区町村や国などの他の属性と同様に、サインアップ時に収集します。 これらの属性とは異なり、ユーザーは後でエイリアスを使用してサインインできます。 エイリアス ("johndoe" など) を使用すると、ユーザーはメール アドレスよりも短く、よりわかりやすい方法でサインインできます。

ユーザー名 (エイリアス) はユーザー名 (電子メール) に置き換えられません。 サインアップ時に、アプリは常にプライマリ識別子としてユーザー名 (電子メール) を収集し、エイリアスを電子メールと共に属性として収集する必要があります。 サインイン時に、ユーザーは自分のユーザー名 (電子メール) またはユーザー名 (エイリアス) を使用してサインインすることを選択できます。

サインアップ ユーザー フローで Username 組み込みユーザー属性が有効になっている場合、SDK は、他の属性に使用されるのと同じ属性ディクショナリを使用して、 flatusername キーとして受け入れます。 signUp呼び出しでユーザー名 (エイリアス) を直接渡すことができるため、ユーザーは別の属性に必要な手順を実行する必要はありません。

ユーザー名 (エイリアス) を収集するには、サインアップ UI のユーザー名の入力フィールドを電子メール フィールドと共に追加し、サインアップ呼び出しで属性としてエイリアスを渡します。

guard let email = emailTextField.text, !email.isEmpty,
      let password = passwordTextField.text, !password.isEmpty,
      let username = usernameTextField.text, !username.isEmpty else {
    showResultText("Please fill in all fields")
    return
}

let attributes: [String: Any] = [
    "flatusername": username
]

let parameters = MSALNativeAuthSignUpParameters(username: email)
parameters.password = password
parameters.attributes = attributes
nativeAuth.signUp(parameters: parameters, delegate: self)

電子メール ワンタイム パスコード フロー (パスワードなし) の場合は、パスワードを設定せずに属性を渡します。

let parameters = MSALNativeAuthSignUpParameters(username: email)
parameters.attributes = attributes
nativeAuth.signUp(parameters: parameters, delegate: self)

ユーザー名 (エイリアス) サインアップのエラーを処理する場合、 error.isUserAlreadyExists プロパティは重複するエイリアスも対象とし、 error.isInvalidAttributes は無効なエイリアス値を表示します。

サインアップ エラーを処理する

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

SignUpStartDelegate プロトコルの以前の実装では、onSignUpStartError(error) デリゲート関数を処理するときにエラーが表示されただけです。

特定のエラーの種類を管理してユーザー エクスペリエンスを高めるために、次のコード スニペットを使用します。

func onSignUpStartError(error: MSAL.SignUpStartError) {
    if error.isUserAlreadyExists {
        resultTextView.text = "Unable to sign up: User already exists"
    } else if error.isInvalidPassword {
        resultTextView.text = "Unable to sign up: The password is invalid"
    } else if error.isInvalidUsername {
        resultTextView.text = "Unable to sign up: The username is invalid"
    } else {
        resultTextView.text = "Unexpected error signing up: \(error.errorDescription ?? "no description")"
    }
}

省略可能: サインアップ フロー後にサインインする

サインアップ フローが正常に完了したら、サインイン フローを開始せずにユーザーをサインインできます。 ユーザーがユーザー名 (エイリアス) でサインアップした場合は、メール アドレスまたはエイリアスを使用してサインインできます。 詳細については、「チュートリアル: iOS アプリでサインアップ後にユーザーをサインインさせる」の記事をご覧ください。

次のステップ