はじめに
皆さん。こんにちは!
DreamHanksのエルムです。
今回は Multi-factor 認証の作成方法について説明していきます。
前回の記事は既存のログインシステムとの併用 – Facebookログインです。
Multi-factor 認証 (AUTHENTICATION)
MFA(Multi-factor 認証)は、ユーザー名(またはエイリアス)とパスワードだけに頼らず、認証方法を追加することで、アプリのセキュリティを高めます。AWS Amplifyでは、Amazon Cognitoを使用してMFAを提供しています。
Amazon CognitoでMFAを有効にしたら、MFAで動作するようにアプリを設定することができます。
TOTPのセットアップ
TOTP(Time-based One-Time Password)では、ユーザー名とパスワードが認証された後に、(TOTP)パスワードを使用して認証を完了するよう、アプリのユーザーに要求します。
アプリ内でユーザーにTOTPを設定することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import { Auth } from 'aws-amplify'; // TOTPを設定するには、まずAmazon Cognitoから「認証コード」を取得する必要があります。 // user`は現在の認証済みユーザー Auth.setupTOTP(user).then((code) => { // コード」を直接ユーザーに表示したり、QRコードに変換してスキャンすることができます。 // 例えば、以下のコードサンプルは、`qrcode.react`コンポーネントを使ってQRコードをレンダリングするものです。 // import QRCode from 'qrcode.react'; // const str = "otpauth://totp/AWSCognito:"+ username + "?secret=" + code + "&issuer=" + issuer; // <QRCode value={str}/> }); // ... // その後、TOTPを生成するアプリ(Google Authenticatorなど)にTOTPアカウントを登録します。 // 生成されたワンタイムパスワードを使って設定を確認することです。 Auth.verifyTotpToken(user, challengeAnswer).then(() => { // TOTPを優先的なMFA方式として設定することを忘れないでください。 Auth.setPreferredMFA(user, 'TOTP'); // ... }).catch( e => { // トークンが検証されていません }); |
MFAタイプの設定
Amazon Cognitoがサポートする複数のMFAタイプ。好みの方法をコードで設定することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { Auth } from 'aws-amplify'; // お好みのmfaタイプを選択できます。 例えば: Auth.setPreferredMFA(user, 'TOTP').then((data) => { console.log(data); // ... }).catch(e => {}); // SMSを選択します。 Auth.setPreferredMFA(user, 'SMS'); // no-mfaを選択します。 Auth.setPreferredMFA(user, 'NOMFA'); |
現在の希望するMFAタイプをコードで取得することができます:
1 2 3 4 5 6 7 8 9 10 |
import { Auth } from 'aws-amplify'; // キャッシュから現在のmfaタイプを取得します。 Auth.getPreferredMFA(user,{ // オプションで、デフォルトではfalseです。 // trueに設定すると、ローカルキャッシュからではなく、サーバー側からMFAタイプを取得します。 bypassCache: false }).then((data) => { console.log('現在の望ましいMFAタイプは ' + data); }) |
ユーザーがMFAタイプを選択できるようにする方法
複数のMFAタイプを使用する場合は、アプリのユーザーに必要な認証方法を選択させることができます。aws-amplify-reactパッケージで提供されているSelectMFAType UI Componentは、利用可能なMFAタイプのリストをレンダリングします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import Amplify from 'aws-amplify'; import awsconfig from './aws-exports'; import { SelectMFAType } from 'aws-amplify-react'; Amplify.configure(awsconfig); // 最低でも2種類は用意してください。 // Cognitoユーザープールに合わせて適切に設定してください。 const MFATypes = { SMS: true, // ユーザープールでSMSが有効になっている場合 TOTP: true, // ユーザープールでTOTPが有効になっている場合 Optional: true, // ユーザープールでMFAがオプションに設定されている場合 } class App extends Component { // ... render() { return ( // ... <SelectMFAType authData={this.props.authData} MFATypes={MFATypes}> ) } } export default withAuthenticator(App, true); |
高度なユースケース
カスタム認証のチャレンジでサインイン (Sign-in with custom auth challenges)
ユーザー名とパスワードを入力してサインインすると、直接サインインするか、認証を受ける前にいくつかの課題に合格するよう求められます。
Auth.signInから返されるユーザーオブジェクトには、challengeNameとchallengeParamが含まれています。この2つのパラメータをもとに、対応する関数を呼び出すことができます。
ChallengeName:
- SMS_MFA: SMSメッセージから受け取ったコードを入力する必要があります。Auth.confirmSignInでコードを送信することができます。
- SOFTWARE_TOKEN_MFA: OTP(one time password)を入力する必要があります。Auth.confirmSignInでコードを送信することができます。
- NEW_PASSWORD_REQUIRED: これは、Cognitoコンソールを通じてユーザーアカウントが作成されたときに発生します。ユーザーは新しいパスワードと必要な属性を入力する必要があります。それらのデータをAuth.completeNewPasswordで提出することができます。
- MFA_SETUP: これは、MFAの方式がTOTP(the one time password)で、ユーザーがパスワードを生成するためにいくつかのステップを踏まなければならない場合に起こります。Auth.setupTOTPでセットアップ作業を開始できます。
以下のコードはデモ用のものです:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
import { Auth } from 'aws-amplify'; async function signIn() { try { const user = await Auth.signIn(username, password); if (user.challengeName === 'SMS_MFA' || user.challengeName === 'SOFTWARE_TOKEN_MFA') { // UI入力からコードを取得する必要があります const code = getCodeFromUserInput(); //MFAが有効な場合は、確認コードでサインインを確認する必要があります。 const loggedUser = await Auth.confirmSignIn( user, // Auth.signIn()からオブジェクトを返します。 code, // 確認用コード mfaType // MFA Type e.g. SMS_MFA, SOFTWARE_TOKEN_MFA ); } else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { const {requiredAttributes} = user.challengeParam; // 必要な属性の配列、例:['email', 'phone_number']. // 新しいパスワードと必要な属性をUI入力から取得する必要があります // 例えば、emailとphone_numberは必須属性です。 const {username, email, phone_number} = getInfoFromUserInput(); const loggedUser = await Auth.completeNewPassword( user, // Cognitoユーザーオブジェクト newPassword, // 新しいパスワード // オプション、必須属性 { email, phone_number, } ); } else if (user.challengeName === 'MFA_SETUP') { // MFA方式がTOTPの場合に発生します。 // TOTPを使用する前にユーザーが設定する必要があります。 // 詳細はEnabling MFAの項をご覧ください。 Auth.setupTOTP(user); } else { // ユーザーが直接サインイン console.log(user); } } catch (err) { if (err.code === 'UserNotConfirmedException') { //サインアップ時にユーザーが確認ステップを完了しなかった場合に発生するエラーです。 // この場合、コードを再送してユーザーを確認する必要があります。 //コードの再送やユーザーの確認方法については、signUp部分をご確認ください。 } else if (err.code === 'PasswordResetRequiredException') { // Cognitoコンソールでパスワードをリセットするとエラーが発生します // この場合、パスワードをリセットするためにforgotPasswordを呼び出す必要があります。 } else if (err.code === 'NotAuthorizedException') { // 不正なパスワードを入力するとエラーになります } else if (err.code === 'UserNotFoundException') { // 提供されたユーザー名/EメールがCognitoユーザープールに存在しない場合にエラーが発生します。 } else { console.log(err); } } } |
Lambda Triggerのカスタム検証データによるサインイン
ユーザー名、パスワード、validationDataを持つオブジェクトを渡して、PreAuthentication Lambda triggerに送信することもできます。
1 2 3 4 5 6 7 8 9 10 |
try { const user = await Auth.signIn({ username, // 必須、ユーザー名 password, // オプション、パスワード validationData, // オプション、 任意のキーを含むことができる任意のキー・バリューペアマップで、そのままPreAuthentication Lambdaトリガーに渡されます。これを使って、認証に関する追加のバリデーションを実装することができます。 }); console.log('user is signed in!', user); } catch (error) { console.log('error signing in:' , error); } |
終わりに
今回の記事は以上になります。
次回は[第8回] パスワード & ユーザー管理を学びましょう。
ご覧いただきありがとうございます。
コメント