初心者向け: React × Flask × DynamoDB でユーザー認証を構築しよう!

※当サイトは、アフィリエイト広告を利用しています。

チーズくん

DynamoDBを設定してみたいんだけど、難しい?

くれとむ

大丈夫!手順を追えば割と簡単に実装できるよ。

今回は、AWS CLIを使ったDynamoDBのセットアップ、Reactで作成したフロントエンドのログインフォーム、Python Flaskによるバックエンド処理を連携させたユーザー認証システムの構築方法をお伝えします。

この記事で学べるポイント
  • DynamoDBのテーブル作成とデータ登録。
  • Reactによるログインフォームとユーザー体験の向上。
  • FlaskでのAPI実装とDynamoDB連携。
本記事で使用するコードのgithub

本ブログで用いているプロジェクトはGitHubリポジトリで公開しています。
以下のリンクからダウンロードしてください。
https://github.com/my-repo-441/dynamodb-login-demo

システム構成

構成要素

本記事でのReact × Flask × DynamoDBによるログインフォーム実装の構成要素は以下です。

構成要素
  • フロントエンド: React
  • バックエンド: Python、Flask
  • データベース: AWS DynamoDB
  • その他ツール: AWS CLI

構成図

システム構成図と処理の流れは以下です。

処理の流れ
  1. 自身のPC(localhost)上でフロントエンドとバックエンドを起動
  2. フロントエンドのログインフォームに、メールアドレスとパスワードを入力
  3. バックエンドからDynamoDBに対して、メールアドレスとパスワードを送信
  4. DynamoDBから取得したメールアドレスとパスワードと一致するかを確認
  5. ログインが成功した場合、「ログイン成功」のメッセージ表示後、ホーム画面に遷移。ログイン失敗した場合、「ログイン失敗」のメッセージ表示後、再度ログインフォームに遷移。

デモアプリの実装

以下に、DynamoDBを使ったログイン処理を含むデモアプリの実装手順を記載します。

くれとむ

ソースコード一式はGithubにアップロードしているので、以下の手順を参考にぜひ自身の環境でも動作させてみてください。

本記事で使用するコードのgithub

本ブログで用いているプロジェクトはGitHubリポジトリで公開しています。
以下のリンクからダウンロードしてください。
https://github.com/my-repo-441/dynamodb-login-demo

前提条件

React × Flask × DynamoDBによるログインフォーム実装を検証するための前提条件は以下です。

前提条件
  • Python:
    • バージョン 3.7 以上がインストールされていること。
    • 確認方法: python --version
  • Node.js:
    • バージョン 14 以上がインストールされていること。
    • 確認方法: node -v
  • npm または Yarn:
    • npm バージョン 6 以上、または Yarn バージョン 1.22 以上。
    • 確認方法: npm -v または yarn -v
  • AWS CLI:
    • AWS CLIがインストールされており、認証が設定されていること。
    • 確認方法: aws --version

事前準備

くれとむ

アプリを実行するために、githubからソースコードをクローンして、フロントエンドとバックエンドの実行に必要なライブラリ一式をインストールします。

githubからソースコード一式をクローン

以下のコマンドで、githubから本プロジェクトで用いるソースコード一式をクローンします。

git clone https://github.com/my-repo-441/dynamodb-login-demo.git

Pythonの仮想環境の作成

以下のコマンドで、Pythonの仮想環境を作成します。

python -m venv your/venv/directory
source your/venv/directory/bin/activate

Pythonライブラリのインストール

以下のコマンドで、バックエンドの実行に必要なPythonライブラリをインストールします。

cd backend
pip install -r requirements.txt

npmライブラリのインストール

以下のコマンドで、フロントエンドの実行に必要なnpmライブラリをインストールします。

cd frontend
npm install
チーズくん

必要なライブラリをインストールできたよ。
次からは、ようやくDynamoDBのセットアップだね。

DynamoDBのセットアップ

最初に、ユーザーデータを管理するDynamoDBのセットアップを行います。

DynamoDBの役割

DynamoDBの役割

DynamoDBはAWSが提供するNoSQLデータベースサービスです。このプロジェクトでは、ユーザーのメールアドレスやパスワードを管理するために使用します。

テーブル作成

以下のPythonコードを使って、DynamoDBテーブル「Users-ReactApp」を作成します。
このテーブルでは、emailをプライマリキー(パーティションキー)として設定します。

  • ap-northeast-1:DynamoDBテーブルを作成するリージョンを入力してください。
  • Users:任意のテーブル名を入力してください。
import boto3
import time
import traceback

dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-1')
table_name = "Users"

def create_dynamodb_table():
    try:
        table = dynamodb.create_table(
            TableName=table_name,
            KeySchema=[
                {'AttributeName': 'email', 'KeyType': 'HASH'}
            ],
            AttributeDefinitions=[
                {'AttributeName': 'email', 'AttributeType': 'S'}
            ],
            ProvisionedThroughput={
                'ReadCapacityUnits': 1,
                'WriteCapacityUnits': 1
            }
        )
        print(f"テーブル {table_name} が作成されました。")
        table.wait_until_exists()
        print("テーブルのステータス:", table.table_status)
    except dynamodb.meta.client.exceptions.ResourceInUseException:
        print(f"テーブル {table_name} は既に存在します。")
    except Exception as e:
        print("エラーが発生しました:")
        traceback.print_exc()

create_dynamodb_table()

実行例

テーブル Users が作成されました。

テーブルのステータス: CREATING
くれとむ

実行が正常に完了した場合は、DynamoDBコンソール画面からテーブルが作成されていることを確認することができます。

チーズくん

プライマリキーには何を設定してもいいの?

くれとむ

うん。今回はユーザーIDとして一意で、検索に適しているから、emailをプライマリキーにしたけど、ユーザーごとに一意の値であれば何でもいいよ。

サンプルデータの登録

次に、DynamoDBにユーザーデータを登録します。
以下のPythonコードを実行することで、DynamoDBテーブル構成を作成します。
パスワードはハッシュ化して保存し、セキュリティを強化します。

  • Table Name: Users
  • Primary Key: email (文字列)
  • test@example.com:任意のメールアドレスを入力。
import boto3
from werkzeug.security import generate_password_hash
from datetime import datetime, timezone
import traceback

dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-1')
table_name = "Users"
table = dynamodb.Table(table_name)

def create_user(email, password, **additional_fields):
    try:
        password_hash = generate_password_hash(password)
        created_at = datetime.now(timezone.utc).isoformat()

        item = {
            'email': email,
            'password_hash': password_hash,
            'created_at': created_at
        }
        # 追加のフィールドを動的に登録
        item.update(additional_fields)

        response = table.put_item(Item=item)
        print(f"ユーザー {email} を登録しました。")
        return response
    except Exception as e:
        print("ユーザー登録中にエラーが発生しました:")
        traceback.print_exc()

# サンプル登録
create_user('test@example.com', 'securepassword123', role='admin')

実行例

ユーザー test@example.com を登録しました。

テーブルが作成されたら、DynamoDBのコンソール画面 -> 「項目を探索」で確認できます。

Reactでフロントエンド構築

Screenshot

フロントエンドでは、Reactを使用してログインフォームを作成し、ユーザー体験を向上させます。

ログインフォームの作成

以下はReactで作成したログインフォームの例です。
メールアドレスとパスワードを入力できるシンプルなフォームです。

import React, { useState } from "react";
import {
  Box,
  Button,
  FormControl,
  FormLabel,
  Input,
  Heading,
  VStack,
  useDisclosure,
} from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import ResultDialog from "../components/ResultDialog";

function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [dialogMessage, setDialogMessage] = useState("");
  const [isSuccess, setIsSuccess] = useState(false);
  const { isOpen, onOpen, onClose } = useDisclosure();
  const navigate = useNavigate(); // React Routerのnavigateフック

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!email || !password) {
      setDialogMessage("メールアドレスとパスワードを入力してください。");
      setIsSuccess(false);
      onOpen();
      return;
    }
    try {
      const response = await fetch("http://127.0.0.1:5000/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password }),
      });

      if (response.ok) {
        setDialogMessage("ログイン成功!");
        setIsSuccess(true);
        onOpen();
        setTimeout(() => {
          onClose();
          navigate("/home");
        }, 2000);
      } else {
        setDialogMessage("ログイン失敗。ユーザーIDまたはパスワードを確認してください。");
        setIsSuccess(false);
        onOpen();
      }
    } catch (error) {
      setDialogMessage("エラーが発生しました。ネットワーク接続を確認してください。");
      setIsSuccess(false);
      onOpen();
    }
  };

  return (
    <Box
      w="100%"
      maxW="400px"
      mx="auto"
      mt="50px"
      p="6"
      boxShadow="lg"
      borderRadius="md"
      bg="white"
    >
      <Heading as="h2" size="lg" textAlign="center" mb="6">
        ログイン
      </Heading>
      <form onSubmit={handleSubmit}>
        <VStack spacing={4}>
          <FormControl id="email" isRequired>
            <FormLabel>メールアドレス</FormLabel>
            <Input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="メールアドレスを入力"
            />
          </FormControl>
          <FormControl id="password" isRequired>
            <FormLabel>パスワード</FormLabel>
            <Input
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              placeholder="パスワードを入力"
            />
          </FormControl>
          <Button
            type="submit"
            colorScheme="blue"
            size="lg"
            width="full"
            mt={4}
          >
            ログイン
          </Button>
        </VStack>
      </form>

      {/* ダイアログ */}
      <ResultDialog
        isOpen={isOpen}
        onClose={onClose}
        cancelRef={null}
        message={dialogMessage}
        isSuccess={isSuccess}
      />
    </Box>
  );
}

export default LoginForm;

上記により、以下のようなログインフォームが表示されるようになります。

ポイント
  • Chakra UIを活用して見た目を整える。
  • fetchを使用してFlaskバックエンドにリクエストを送信。

Flaskでバックエンド構築

バックエンドでは、Flaskを使ってReactからのリクエストを受け取り、DynamoDBと連携します。

処理の概要

フロントエンドからのリクエスト取得

以下の部分で、フロントエンドから送信されたリクエスト(メールアドレスとパスワードを取得しています。)

@app.route("/login", methods=["POST"])
def login():
    data = request.json
    email = data.get("email")
    password = data.get("password")
    ...
DynamoDBのクエリ処理

以下の部分で、DynamoDBのクエリ処理を行なっています。
具体的には、ユーザー情報を取得して検証する処理。セキュリティ対策として、保存されたパスワードハッシュと入力されたパスワードを比較しています。

user = table.get_item(Key={"email": email}).get("Item")
if user and check_password_hash(user["password_hash"], password):
    return jsonify({"message": "ログイン成功!"}), 200
CORSの実装

フロントエンドとの通信を可能にするためにFlask-CORSを実装しています。

from flask_cors import CORS
CORS(app)
ポイント
  • DynamoDBからユーザーデータを取得
    • パスワードをハッシュ化して保存し、check_password_hashで検証。
  • レスポンス設計
    • 成功時と失敗時で適切なHTTPステータスコードを返す。

フロントエンドとバックエンドの統合

Reactアプリを実行し、Flaskバックエンドと通信できるようにします。

Reactアプリの起動

以下のコマンドでReactアプリを起動します。

npm run dev

出力例

  VITE v4.5.5  ready in 130 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

Flaskサーバーの起動

Flaskバックエンドを起動します。

python app.py

出力例

 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 142-848-122

動作確認

以下の手順で動作確認を行います。

手順:動作確認
  1. Webアプリにアクセス
    • npm run devで起動したhttp://localhost:3000にアクセスします。
  2. ログインフォームの入力およびバックエンドへの送信
    • ReactのログインフォームからユーザーIDとパスワードを入力し、ログインボタンを押下します。
      (FlaskサーバーがDynamoDBを参照し、ログイン情報を確認します。)
  3. ログイン処理の確認
    • 「ログイン成功!」のメッセージが表示され、ホーム画面に遷移することを確認します。メールアドレスもしくはパスワードが異なる場合に、ログイン失敗のメッセージ表示されることも確認します。

Webアプリにアクセス

npm run devで起動したhttp://localhost:3000にアクセスします。

ログインフォームの入力およびバックエンドへの送信

くれとむ

DynamoDBテーブル項目に追加したメールアドレスとパスワードを入力します。

補足:メールアドレスとパスワードについて

ログインフォームで入力するメールアドレスとパスワードは、DynamoDBにテーブル項目を追加した際の以下のコードが該当します。

# サンプル登録
create_user('example.com@gmail.com', 'securepassword123')

ログイン処理の確認

ログイン成功した場合
くれとむ

ログインに成功した場合は、以下のような画面遷移が行われます。

↓↓
ホーム画面に遷移
↓↓

ログインに失敗した場合
くれとむ

DynamoDBに登録したテーブル項目とは異なるメールアドレスとパスワードを入力すると、ログインに失敗します。
ログインに失敗した場合は、メッセージが表示されます。

まとめ

チーズくん

数ステップでFlaskとDynamoDBを使ったユーザー認証が実装できたね。

くれとむ

実際には、CORS対策やJWTによる認証セッションの管理など、他にも実装する必要があるんだけど、ユーザー認証の基本はこれで掴めたかな。

React、Flask、DynamoDBを連携して、ログイン機能を構築する方法を紹介しました。
これを応用すれば、実用的なアプリケーションを簡単に作ることができます。

本プロジェクトのソースコードと手順を参考に、ぜひ試してみてください。
最後まで読んでいただきありがとうございました。










コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


ABOUT US
くれとむ
IT企業で働いているシステムエンジニアです。 AWSなどIT技術のトレンドを発信します。 また、日常の課題を解決するライフハック記事や実体験をもとにしたレビューも発信します。 エンジニアならではの視点で、技術の楽しさと日常の快適さを繋げます! AWS認定(CLF, SAA, DVA, SOA, SAP, DOP, ANS, SCS, MLS)、基本情報技術者、応用情報技術者、情報処理安全確保支援士、TOEIC L&R 870点 ※このサイトはアフィリエイト広告(Amazonアソシエイト含む)を掲載しています。