Flutter3 と Amplify UI Components で MFA(SMS)が有効な認証つきアプリを作ってみました

Flutter3 と Amplify UI Components で MFA(SMS)が有効な認証つきアプリを作ってみました

2022.09.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

CX事業本部デリバリー部の平内(SIN)です。

Flutterでの利用も提供されている、Amplify UI Componentsを使用すると、Cognitoと組み合わせて、ユーザーログインが簡単に準備できます。 なお、Amplify UI Componentsは、MFAにも対応しているため、Cognito側で設定を有効にするだけで、特に実装を追加する必要はありません。

今回は、Amplify UI Componentsを使用して、MFA対応の認証付きアプリを作成してみました。 ログイン時、及び、パスワードを忘れた場合(パスワード変更時)に、MFA(SMSに送られた検証コードの入力)が必要になります。

最初に、作成したアプリが動作している様子です。

ログイン時は、ユーザー名及び、パスワードに加えて、SMSに送られた検証コードの入力が必要です。 なお、一度ログインが完了するとログアウトしない限り、リフレッシュトークンの有効な期間(今回は30日と設定)は、認証なしで開けます。

2 動作環境

今回使用したバージョンは、以下の通りです。

			
			
% amplify --v
9.2.1

		
			
			
% flutter --version
Flutter 3.3.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision e3c29ec00c (8 days ago) • 2022-09-14 08:46:55 -0500
Engine • revision a4ff2c53d8
Tools • Dart 2.18.1 • DevTools 2.15.0

		

3 Flutterでのアプリ作成

最初に、Flutterアプリを作成し、必要なライブラリを追加します。

			
			
% flutter create sample_app
% cd sample_app
% flutter pub add amplify_flutter
% flutter pub add amplify_auth_cognito
% flutter pub add amplify_authenticator

		

4 Amplify(Auth)設定

続いて、Amplifyを初期化します。

			
			
% amplify init

		

Authの追加は、マニュアルで行います。

			
			
% amplify add auth
 Do you want to use the default authentication and security configuration?
  Default configuration
  Default configuration with Social Provider (Federation)
❯ Manual configuration
  I want to learn more.

		

使用するのは、サインアップとサインインのみです。

			
			
 Select the authentication/authorization services that you want to use:
  User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features for images or other content, Analytics, and more)
❯ User Sign-Up & Sign-In only (Best used with a cloud API only)
  I want to learn more.

		

プロジェクト名及び、ユーザープール名は、デフォルトのままとしました。

			
			
Provide a friendly name for your resource that will be used to label this category in the project:
 sampleapp519f64ce519f64ce
Provide a name for your user pool: 
 sampleapp519f64ce_userpool_519f64ce

		

ログインは、ユーザー名を使用することにします。

			
			
 How do you want users to be able to sign in? (Use arrow keys)
❯ Username
  Email
  Phone Number
  Email or Phone Number
  I want to learn more.

		

UserPoolのグループ、管理用APIは、いづれもONとしました。

			
			
 Do you want to add User Pool Groups?
❯ No
 Do you want to add an admin queries API?
❯ No

		

ここが、MFAの設定ですが、認証時必須とし、SMSを用いるよう設定します。

			
			
 Multifactor authentication (MFA) user login options:
  OFF
❯ ON (Required for all logins, can not be enabled later)
  OPTIONAL (Individual users can use MFA)
  I want to learn more.

		
			
			
 For user login, select the MFA types: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ SMS Text Message
 ◯ Time-Based One-Time Password (TOTP)

		

SMSのメッセージの設定や認証コードを送るEメールの設定です。 デフォルトのまま。

			
			
 Specify an SMS authentication message: (Your authentication code is {####})

		

パスワードを忘れた場合は、SMSを使用するようにします。

			
			
 Email based user registration/forgot password:
  Enabled (Requires per-user email entry at registration)
❯ Disabled (Uses SMS/TOTP as an alternative)

		

この時のSMSメッセージもデフォルトのままとしています。

			
			
Please specify an SMS verification message: (Your verification code is {####})

		

デフォルトのパスワードポリシーは、そのまま利用します。

			
			
 Do you want to override the default password policy for this User Pool? (y/N)

		

サインアップ時に必要な情報は、すべてのチェックを外しておきます(電話番号は自動的に必須となります)

			
			
 What attributes are required for signing up?
 ◯ Zone Info (This attribute is not supported by Facebook, Google, Login With Amazon, Signinwithapple.)
 ◯ Address (This attribute is not supported by Facebook, Google, Login With Amazon, Signinwithapple.)
 ◯ Birthdate (This attribute is not supported by Login With Amazon, Signinwithapple.)
❯◯ Email
 ◯ Family Name (This attribute is not supported by Login With Amazon.)
 ◯ Middle Name (This attribute is not supported by Google, Login With Amazon, Signinwithapple.)
 ◯ Gender (This attribute is not supported by Login With Amazon, Signinwithapple.)

		

トークンの有効期限は、デフォルトの30日です。

			
			
 Specify the app's refresh token expiration period (in days): 30
 Do you want to specify the user attributes this app can read and write? No

		

機能の追加、ソーシャルログイン、Lmabda関数のトリガーは特に使い予定がないため選択無しで行っていきます。

			
			
 Do you want to enable any of the following capabilities? (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯ ◯ Add Google reCaptcha Challenge
 ◯ Email Verification Link with Redirect
 ◯ Add User to Group
 ◯ Email Domain Filtering (denylist)
 ◯ Email Domain Filtering (allowlist)
 ◯ Custom Auth Challenge Flow (basic scaffolding - not for production)
 ◯ Override ID Token Claims

		

OAuthフローは、未使用です。

			
			
 Do you want to use an OAuth flow?
  Yes
❯ No
  I want to learn more.

		
			
			
? Do you want to configure Lambda Triggers for Cognito? (Y/n) N

		

マニュアルによる設定が完了したらpushします。

			
			
% amplify push

		

5 SMS送信

AmplifyのAuth設定で、SMSを有効にすると、下記のような警告が表示されます。

			
			
⚠️ You have enabled SMS based auth workflow. Verify your SNS account mode in the SNS console: https://console.aws.amazon.com/sns/v3/home#/mobile/text-messaging
If your account is in "Sandbox" mode, you can only send SMS messages to verified recipient phone numbers.

		

AWSアカウントのSMS送信は、当初、サンドボックスモードとなっているため、認証に使用する電話番号は、検証済みとする必要があります。

SMSサンドボックスを終了し、本稼働にすいれば、電話番号の検証は必要なくなります。

また、アカウントの使用制限は、デフォルトで1USD/月となっています。

日本宛に送信する場合のSMS料金は1通あたり$0.07451であるため、1月あたり、13 通程度でリミットとなってしまいます。 これ以上の送信をする場合は、上限緩和申請、及び、ここでの設定値を変更する必要があります。

https://aws.amazon.com/jp/sns/sms-pricing/?nc1=h_ls

上限緩和申請する場合のサービスクォータの名称は、SMS Message Spending in USDです。

6 Flutterの実装

実装したのコードは、以下の通りです。

認証周りについては、Amplify UI Componentsに全てお任せとなっています。

lib/main.dart

			
			
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:sample_app/amplifyconfiguration.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _amplify = Amplify;

  @override
  initState() {
    super.initState();
    _configureAmplify();
  }

  Future<void> _configureAmplify() async {
    try {
      await _amplify.addPlugins([
        AmplifyAuthCognito(),
      ]);
      await _amplify.configure(amplifyconfig);
    } catch (e) {
      debugPrint(e.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Authenticator(
      child: MaterialApp(
        debugShowCheckedModeBanner: true,
        theme: ThemeData(
          primarySwatch: Colors.red,
        ),
        builder: Authenticator.builder(),
        home: const HomePage(),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  final title = 'Sample';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      drawer: AppDrawer(
        title: title,
      ),
      body: const Center(
        child: Text(
          "Hello World.",
        ),
      ),
    );
  }
}

class AppDrawer extends StatelessWidget {
  const AppDrawer({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: SingleChildScrollView(
        child: Column(
          children: [
            AppBar(
              title: Text(title),
              automaticallyImplyLeading: false,
            ),
            ListTile(
              leading: const Icon(Icons.exit_to_app),
              title: const Text('Logout'),
              onTap: () {
                Amplify.Auth.signOut();
              },
            ),
          ],
        ),
      ),
    );
  }
}


		

7 最後に

今回は、Amplify UI Componentsを使用して、MFA対応の認証付きアプリを作成してみました。 認証周りは、自前で実装なると、準備するページを沢山あって、結構手間がかかります。提供されるコンポーネントで表現できる範囲で治ると、助かるのですが・・・

この記事をシェアする

FacebookHatena blogX

関連記事