Flutter3 と Amplify UI Components で MFA(SMS)が有効な認証つきアプリを作ってみました
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対応の認証付きアプリを作成してみました。 認証周りは、自前で実装なると、準備するページを沢山あって、結構手間がかかります。提供されるコンポーネントで表現できる範囲で治ると、助かるのですが・・・