LoginSignup
53
56

More than 3 years have passed since last update.

【React】ユーザー認証をCognito + Amplifyで構築してみた ~ 構築完成編 ~

Last updated at Posted at 2020-11-25

はじめに

Reactで作成したWebアプリケーションのユーザー認証部分をCognito + Amplifyフレームワークで構築してみました。
本記事では、Cognitoのユーザープールの作成方法、Reactでのコード実装についてまとめています。

完成画面

今回は、ユーザー名、パスワードとワンタイムパスワードの2段階認証を行います。そして、サインインをしたユーザーを識別し、トップページには「{ユーザー名}さんこんにちは!」という文字が出るようにします。

ezgif.com-gif-maker.gif

方法検討

要件

認証方法を考えるにあたり、条件は以下の通りです。

  • 静的コンテンツをS3に置いている
  • アプリケーション部分はLambdaで実装している
  • アプリケーション内でユーザーを管理しており、ユーザーに登録されている人だけ使えるようにしたい
  • 今後ユーザーのマイページも作りたいので、認証と合わせてユーザーを識別したい
  • パスワードはシステム管理者が管理しないようにするのがベター
  • ソーシャルアカウントは使わない
  • MFA(多要素認証)を使いたい

結論

この条件に沿って認証部分を考えた結果、Cognitoを利用することにしました。また、Cognitoと既存のWebアプリケーションを簡単に連携できるAWSのAmplifyフレームワークというものがあったので、こちらも使ってみることにしました。

手順

下記の流れで進めていきます。

下記の1番から4番については別記事 構築準備編 へ。
1. Reactの開発環境の構築
2. Amplifyの設定
3. Amplify用のIAMユーザーの作成
4. Amplifyの初期設定

本記事ではこちらの手順についてまとめています。
5. Cognitoユーザープールの作成
6. コード実装

やってみる

5. Cognitoユーザープールの作成

前述の要件に沿ってユーザープールを作成していきます。
初めてのCognitoで何の設定をしているのかを調べるのが大変だったので1つ1つ残しておこうと思います。

Cognitoの作成を行うために下記のコマンドを実行します。

$ amplify add auth

詳細な設定を行うか、デフォルトの設定で良いか聞かれます。今回はMFAを使いたかったのでManual configurationを選択しました。


# Do you want to use the default authentication and security configuration?
Manual configuration

今回はサインインが使えれば良かったので、User Sign-Up & Sign-In only (Best used with a cloud API only)を選択しました。


# Select the authentication/authorization services that you want to use:
User Sign-Up & Sign-In only (Best used with a cloud API only)

リソース名とユーザープール名を入力します。


# Please provide a friendly name for your resource that will be used to label this category in the project: 
test
# Please provide a name for your user pool: 
test-cognito-mfa

ユーザー名とパスワードでサインインしたいので、Usernameを選択します。この項目は、後から変更できません。


# How do you want users to be able to sign in?
Username

参考
スクリーンショット 2020-11-01 14.47.16.png

今回はグループは作成しないのでNoを選択します。


# Do you want to add User Pool Groups? 
No

ユーザープール内の情報を取得したり、ユーザーを登録したりするAPIを叩けるようにするかを選択します。今回は使わないのでNoを選択します。
参考:https://docs.amplify.aws/cli/auth/admin


# Do you want to add an admin queries API?
No

今回はアプリケーション内でユーザーを管理していたため、このAPIを使わずに、自分でLambdaを作成しAWSのSDKを使ってユーザーの登録などを実装しましたが、このAPI使うのでも良かったかもしれないです。

MFAの設定を行います。今回はMFAを使いたいのでONを選択します。この設定はあとで変えられないので気をつけましょう。そして、MFAにはAuthenticatorやAuthyなどのアプリケーションを用いてのワンタイムパスワードを使いたいので、TOTPのみを選択しました。


# Multifactor authentication (MFA) user login options:
 ON (Required for all logins, can not be enabled later)
# For user login, select the MFA types: 
 Time-Based One-Time Password (TOTP)

参考
スクリーンショット 2020-11-03 19.28.34.png

SMSのメッセージの設定です。
SMSは使わず、Eメールを使うつもりなので、デフォルトのままEnterします。


# Please specify an SMS authentication message: 
 Your authentication code is {####}

ユーザープールにはEメールアドレスも登録し、Eメールを使ってユーザーの登録やパスワードの再設定を行いたいのでEnabledを選択します。


# Email based user registration/forgot password:
Enabled (Requires per-user email entry at registration)

参考(左メニュー [MFAそして確認] 内)
スクリーンショット 2020-11-03 23.37.46.png

認証コードを送るEメールの題名と本文の設定です。デフォルトのまま進みます。


# Please specify an email verification subject:
Your verification code
# Please specify an email verification message:
Your verification code is {####}

参考(左メニュー [メッセージのカスタマイズ] 内)
スクリーンショット 2020-11-06 23.10.00.png

パスワードポリシーを設定します。
文字数を8文字以上、数字、特殊文字、大文字、小文字を含むパスワードのみしか設定できないようにしました。


# Do you want to override the default password policy for this User Pool?
Yes
# Enter the minimum password length for this User Pool:
8
# Select the password character requirements for your userpool:
Requires Lowercase, Requires Uppercase, Requires Numbers, Requires Symbols

参考
スクリーンショット 2020-11-01 14.14.27.png

ちなみに、Do you want to override the default password policy for this User Pool?No (= デフォルトのパスワード設定)とすると、8文字以上という条件しか設定されません。

サインアップ時に必要な属性を設定します。パスワードの再設定等にメールアドレスを使用するため、Emailを選択しました。この項目は、後から変更できません。


# What attributes are required for signing up?
Email

参考(左メニュー [属性] 内)
スクリーンショット 2020-11-01 14.50.07.png

リフレッシュトークンはひとまずデフォルトの30日にしておきます。


# Specify the app's refresh token expiration period (in days): 
30

参考
スクリーンショット 2020-11-01 14.35.36.png

サインアップはユーザー自身が行わず別の処理で行うので書き込み権限は付与しません。また、ログインしたユーザーの識別にはUsernameを使うので読み取り権限も付与しません。


# Do you want to specify the user attributes this app can read and write?
No

今回は、アプリケーション内で事前に登録しているユーザーのみしかログインできず、ユーザー自身がサインアップすることがないので追加しませんでしたが、下記のような機能を追加することもできます。

  • Add Google reCaptcha Challenge
  • Email Verification Link with Redirect
  • Add User to Group
  • Email Domain Filtering (blacklist)
  • Email Domain Filtering (whitelist)
  • Custom Auth Challenge Flow (basic scaffolding - not for production)

# Do you want to enable any of the following capabilities? 
(選択なし)

今回はソーシャルログインは使わないのでOAuthはNoを選択します。


# Do you want to use an OAuth flow?
No

CognitoをLambda関数のトリガーとして使う予定はなかったのでnを入力。
例えば、ユーザーがサインアップしたことをトリガーとしてLambda関数を実行したいときなどに利用できます。


# Do you want to configure Lambda Triggers for Cognito?
No

参考
スクリーンショット 2020-11-01 14.22.29.png

これで構築するCognitoの設定が完了です。
そして、下記のコマンドで設定を保存します。

$ amplify push

環境やリソースがあっているかを聞かれるので、確認してyを入力します。


# ? Are you sure you want to continue?
Yes

これでCognitoのユーザープールが作成されました!そしてsrc/aws-exports.jsにはid等が書き込まれます。

最後に、このままだとユーザー自身がサインアップできてしまうので、Cognitoコンソールからできないようにします。
先ほど作成したCognitoのユーザープールを開き、左のメニューから[ポリシー]をクリックし、[管理者のみにユーザーの作成を許可する]を選択します。その後、[変更の保存]をクリックし、保存してください。

スクリーンショット 2020-11-03 23.27.48.png

Cognitoのコンソールからも設定を変更することもできますが、一部コンソールの変更では反映されないというのも見かけましたので、ご注意ください。Amplify CLIで設定を変更する場合は、$ amplify update authで設定を変更し、$ amplify pushを実行することで変更が保存されます。

6. コード実装

App.jsの中身を書き換えます。
参考:https://docs.amplify.aws/lib/auth/getting-started/q/platform/js

App.js

import React, {useEffect} from "react";
import Amplify, {Auth} from 'aws-amplify';
import awsconfig from './aws-exports';
import {withAuthenticator} from "@aws-amplify/ui-react";

Amplify.configure(awsconfig);

function App() {
    const [currentUserName, setCurrentUserName] = React.useState("");
    useEffect(() => {
        const init = async() => {
            const currentUser = await Auth.currentAuthenticatedUser();
            setCurrentUserName(currentUser.username);
        }
        init()
    }, []);

    const signOut = async() => {
        try {
            await Auth.signOut();
        } catch (error) {
            console.log('error signing out: ', error);
        }
        document.location.reload();
    }

    return (
        <div>
            <h1>{currentUserName}さんこんにちは</h1>
            <button onClick={signOut}>サインアウト</button>
        </div>
    );
}

export default withAuthenticator(App);

実行結果

ユーザーの追加

ユーザーの追加を行います。まだ、アプリケーション内から登録ができるようになっていないので、今回はAWSのCognitoコンソールから追加を行います。

先ほど作成したユーザープール内の左メニュー[ユーザーとグループ]を選択し、[ユーザーの作成]をクリックします。

スクリーンショット 2020-11-07 16.37.01.png

ユーザー名、ユーザーへの招待はEメールで行いたいのでEメールにチェック、電話番号は登録しないので検証済みのチェックを外し、Eメールアドレスを入力します。そして、[ユーザーの作成]をクリックし、ユーザーを作成します。ここで仮パスワードを未入力で登録すると、ユーザーにはランダムでパスワードが発行されます。

スクリーンショット 2020-11-07 16.43.13.png

ユーザーが作成できました。

スクリーンショット 2020-11-07 16.43.58.png

これでユーザーの登録は完了です。そしてユーザーには次のようなメールが送られます。

スクリーンショット 2020-11-07 16.44.59.png

サインイン一連の流れ(2回目以降)

冒頭の完成画面をご覧ください。
※初回サインイン時には、パスワードの変更、TOTP用のQRコードを読み取る操作が加わります。

サインインページからアカウントは本当につくれないのか

最後にAWSコンソールからユーザーがサインアップできないように設定しましたが、本当にできないのかを試してみます。

スクリーンショット 2020-11-07 18.01.02.png

エラーが出てサインイン画面からは登録できないことが確認できました!

おわりに

こんなに簡単にユーザー認証をつけることができました!画面もAmplifyのUIコンポーネントを使えば、こんなにも簡単に作成することができるんです!
ただ、このままではサインインページに使えないアカウント作成ボタンがあるので、そのボタンをなくしたい、AWSコンソールからではなくアプリケーションでユーザー管理できるようにしたいなど、要件に合うように多少カスタマイズも必要です。そのカスタマイズについて今後記事に残していければと思います。

53
56
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
53
56