[Flutter] Amazon Cognitoオーソライザーを設定したAPI Gateway REST APIを叩いてデータを取得する

2023.03.09

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

こんにちは、CX事業本部 Delivery部の若槻です。

今回は、FlutterアプリからAmazon Cognitoオーソライザーを設定したAPI Gateway REST APIを叩いてデータを取得する実装をしてみました。

実装

バックエンド側

バックエンド側は詳述はしませんが、次のような構成となります。

  • Amazon API Gateway REST API
  • Amazon Cognito Authorizer
  • Lambda Function

実装方法は以前投稿した下記などが参考になりますので参照ください。

/usersパスをGETメソッドで叩くと、ユーザーデータのリストが取得できます。

[
  {
    "email":"user01@example.com",
    "id":"d0357bd7-f545-4f94-83dc-47b47cbf53d5"
  },
  {
    "email":"user02@example.com",
    "id":"7032aecb-11ae-4e6d-bf48-7b67ef5dbbed"
  }
]

モバイルアプリ側

モバイルアプリ側です。今回はProviderを使っていないのでmain.dartで単一のWidgetで実装しています。

またAmplify SDKを使用したCognito認証の実装は高橋雄大さんの記事を大いに参考にさせて頂きました。

lib/main.dart

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

import 'amplifyconfiguration.dart';

const apiDomain = 'xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com'; //API Gatewayのドメインを指定

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

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

class _MyAppState extends State<MyApp> {
  bool signedIn = false;
  String idToken = '';
  List items = [];

  Future<void> _configure() async {
    try {
      await Amplify.addPlugin(AmplifyAuthCognito());
      await Amplify.configure(amplifyconfig);

      try {
        await Amplify.Auth.getCurrentUser();

        setState(() {
          signedIn = true;
        });
      } on AuthException {
        setState(() {
          signedIn = false;
        });
      }

      print('Successfully configured');
    } on Exception catch (e) {
      print('Error configuring Amplify: $e');
    }
  }

  @override
  void initState() {
    super.initState();
    _configure();
  }

  Future<void> signIn() async {
    try {
      await Amplify.Auth.signInWithWebUI();

      setState(() {
        signedIn = true;
      });
    } on AuthException {
      setState(() {
        signedIn = false;
      });
    }
  }

  Future<void> signOut() async {
    try {
      await Amplify.Auth.signOut();

      setState(() {
        signedIn = false;
      });
    } on AuthException {
      setState(() {
        signedIn = true;
      });
    }
  }

  // IDトークン取得
  Future<void> getIdToken() async {
    try {
      var response = await Amplify.Auth.fetchAuthSession(
          options: CognitoSessionOptions(getAWSCredentials: true));

      if (!response.isSignedIn) {
        throw Exception('Auth session expired.');
      }

      var session = response as CognitoAuthSession;

      setState(() {
        idToken = session.userPoolTokens!.idToken;
      });
    } on Exception {
      signedIn = false;
    }
  }

  // IDトークンを使用してREST APIを叩きデータを取得
  Future<void> getData() async {
    if (idToken != '') {
      http.Response response = await http.get(
          Uri.https(
            apiDomain,
            '/v1/users',
          ),
          headers: {'Authorization': idToken});

      setState(() {
        items = json.decode(response.body);
        print(items);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    getIdToken();

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ホーム')),
        body: Center(
            child: signedIn
                ? items.isEmpty
                    ? ElevatedButton(
                        child: const Text('データ取得'),
                        onPressed: () {
                          getData();
                        })
                    : ListView.builder(
                        itemCount: items.length,
                        itemBuilder: (BuildContext context, int index) {
                          return Card(
                            child: Column(
                              children: <Widget>[
                                ListTile(
                                  title: Text(items[index]['id']),
                                  subtitle: Text(items[index]['email']),
                                ),
                              ],
                            ),
                          );
                        },
                      )
                : ElevatedButton(
                    child: const Text('ログイン'),
                    onPressed: () {
                      signIn();
                    })),
      ),
    );
  }
}

動作確認

サインイン前はログインボタンが表示されます。

ログインボタンをクリックしてCognitoのHosted UIを表示し、サインインを行います

サインインできました。サインイン後にはデータ取得ボタンが表示されます。

取得ボタンをクリックするとデータが取得され、ListViewに表示することができました。

おわりに

FlutterアプリからAmazon Cognitoオーソライザーを設定したAPI Gateway REST APIを叩いてデータを取得する実装をしてみました。

FlutterアプリのAPIバックエンドにAWSを採用する場合はよくある構成だと思います。

参考

以上