LoginSignup
6

More than 3 years have passed since last update.

AWS CognitoでのauthenticateUser(ログイン)処理で呼ばれる関数を調べてみた。

Last updated at Posted at 2019-12-14

背景

AWS使ってサーバーレスで自分用の家計簿的なwebサービスを勉強も兼ねて開発中。Cognitoでログイン制御は出来た(前回の記事)。 しかし、どうもすっきりしない部分がある。

すっきりしない部分

新しいパスワード入れた後、以下のエラーがブラウザコンソール出てきた。completeNewPasswordChallenge 関数のcallbackもちゃんと実装必要があるはずだが、今回はスルー。Failしたと思われるが、ユーザーのステータスをAWSコンソールで確認するとCONFIRMEDになっていたし。今後ここらへんもうちょっとちゃんとすることにする。

前提

  • MFAは使用しない
  • 管理者のみユーザー追加可能。その際は仮パスワード。
  • ユーザーにパスワード変更を求める

調べると、同じような事を感じた人がいる様子。
似たケース

修正

テストのために、一旦ユーザー削除。※ボタンが表示されず、削除できないのか?と思ったが、一旦 ユーザーを無効化 すると ユーザーを削除 ボタンが出てきた。※ちなみに、ユーザー作成時、E メールを検証済みにしますか? にチェックを入れるとメールが飛んでこない様子。

どんなcallbackが必要なのかちゃんと調べる。VSCodeだと、関数にマウスを合わせると引数の型を表示してくれる。callbackにどんなメソッドが必要かも解る。素晴らしい。
image.png

callback関数を指定する引数がthisになっている。これがcallback引数全体を指しているならonFailureもちゃんと実装している。この部分がthisになってるのが関係してる疑惑。サンプルロジックから考えるとどうやらcallbackは再帰呼び出し的に使いまわしするものらしい。callbacksを外に出してみる。

修正したlogin関数部分
  login (username, password) {
    const userData = { Username: username, Pool: this.userPool }
    const cognitoUser = new CognitoUser(userData)
    const authenticationData = { Username: username, Password: password }
    const authenticationDetails = new AuthenticationDetails(authenticationData)
    return new Promise((resolve, reject) => {
      var callbacks = {
        onSuccess: (result) => {
          resolve(result)
        },
        onFailure: (err) => {
          reject(err)
        },
        newPasswordRequired: (userAttributes, requiredAttributes) => {
          var newPass = window.prompt('Please input your new Password', 'Your input will not be masked. please make sure there is no other person.')
          cognitoUser.completeNewPasswordChallenge(newPass, {}, callbacks)
        }
      }
      cognitoUser.authenticateUser(authenticationDetails, callbacks)
    })
  }

エラー出なくなった。this参照が意図しない形になっていた様子。onFailureのエラーが出ていたのは、エラー実処理をしようとしていたのではなく、単に参照してる部分があったという事かと思われる。
公式サンプル でもthisは使っているが、今回参考にさせてもらったソースではPromiseの内部で処理してたりするので、thisがずれていたのだと思う。

調査

せっかくなので、ちゃんと調べてみる。VSCodeで、cognitoUser.authenticateUser 部分をホバーしてみると、第二引数は callbacks。形式は IAuthenticationCallback という事が分かる。公式ソースの IAuthenticationCallback 部分 を見ると、以下の関数がcallbacksに存在する事が解る。

  • onSuccess
  • onFailure
  • newPasswordRequired
  • mfaRequired
  • totpRequired
  • customChallenge
  • mfaSetup
  • selectMFAType

completeNewPasswordChallengeのcallback部分 を見てみると、callbacksは以下の関数。ほぼ重なるものの、違う。

  • onSuccess
  • onFailure
  • mfaRequired
  • customChallenge
  • mfaSetup

多分、今までのはただうまく行っていただけと思われる。厳密にいえば再帰的に同じcallbacksを使うのではなくて、ちゃんとそれぞれのcallbacksを用意すべきと思われる。まぁ、当然ですね。認証の各ステップ毎に求められる処理は違うはず。もちろん同じ処理は共通関数にするとして、callbacksまるごと共有にするのは違っていたと思います。onFailureにしても、フェーズによって次の処理が違うと思うし。自分のケースでは、completeNewPasswordChallengeでの成功&失敗が認証全体の成功&失敗だったから問題なかっただけかと。

IAuthenticationCallbackの各関数内ですべき処理をまとめてみる(※実践してないです。調査結果です。間違ってたらごめんなさい。コメントもらえると有り難いです)。

callbacks内関数 呼ばれる時 すべき処理 その処理に使う関数名 参考リンク
onSuccess サインイン成功 トークン取得とか アプリによる
onFailure サインイン失敗 エラーメッセージとか アプリによる
newPasswordRequired 仮パスワードログイン成功後 ユーザー入力の新しいパスワード渡す cognitoUser.completeNewPasswordChallenge 参考
mfaRequired サインインに SMS_MFA が必要な場合 ユーザー入力認証コードを送る cognitoUser.sendMFACode 参考
totpRequired サインインに TOTP(ワンタイムパスワード) が必要な場合 ユーザー入力認証コードを送る cognitoUser.sendMFACode 参考
customChallenge 特殊認証追加してる場合 内容による cognitoUser.sendCustomChallengeAnswer
mfaSetup TOTP(ワンタイムパスワード)有効時の初回 associateSecretCodeを含むcallbackを渡し、その中でsecretCodeをユーザーデバイスに登録してもらう。 cognitoUser.associateSoftwareToken、cognitoUser.verifySoftwareToken 参考
selectMFAType MFAの種類が選べる時 SMSかTOTPか指定("SMS_MFA"か"SOFTWARE_TOKEN_MFA") cognitoUser.sendMFASelectionAnswer 参考

今回の件で得た豆知識

  • Cognitoユーザープールでは、ユーザーは無効化してからでないと削除できない
  • javaScriptの this は取扱注意。特に多人数で扱うソースの場合はどのオブジェクトを指すかすぐには解りにくいと思う。処理位置などを変更すると影響出てきそう。
  • VSCodeだと(多分他のプログラム用エディタでも)、javaScript関数にマウスを合わせると引数の型を表示してくれる。

参考にさせてもらったページ

Amazon Cognitoのワンタイムパスワード(TOTP)認証をNode.jsで試してみた

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6