背景
AWS使ってサーバーレスで自分用の家計簿的なwebサービスを勉強も兼ねて開発中。Cognitoでログイン制御は出来た(前回の記事)。 しかし、どうもすっきりしない部分がある。
すっきりしない部分
新しいパスワード入れた後、以下のエラーがブラウザコンソール出てきた。completeNewPasswordChallenge 関数のcallbackもちゃんと実装必要があるはずだが、今回はスルー。Failしたと思われるが、ユーザーのステータスをAWSコンソールで確認するとCONFIRMEDになっていたし。今後ここらへんもうちょっとちゃんとすることにする。
前提
- MFAは使用しない
- 管理者のみユーザー追加可能。その際は仮パスワード。
- ユーザーにパスワード変更を求める
調べると、同じような事を感じた人がいる様子。
似たケース
修正
テストのために、一旦ユーザー削除。※ボタンが表示されず、削除できないのか?と思ったが、一旦 ユーザーを無効化 すると ユーザーを削除 ボタンが出てきた。※ちなみに、ユーザー作成時、E メールを検証済みにしますか? にチェックを入れるとメールが飛んでこない様子。
どんなcallbackが必要なのかちゃんと調べる。VSCodeだと、関数にマウスを合わせると引数の型を表示してくれる。callbackにどんなメソッドが必要かも解る。素晴らしい。
callback関数を指定する引数がthisになっている。これがcallback引数全体を指しているならonFailureもちゃんと実装している。この部分がthisになってるのが関係してる疑惑。サンプルロジックから考えるとどうやらcallbackは再帰呼び出し的に使いまわしするものらしい。callbacksを外に出してみる。
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関数にマウスを合わせると引数の型を表示してくれる。