Cognito をローカルで検証してみたい人向けの記事です
内容
-
Docker
- 仮想AWSサーバー(
motoサーバー
)の起動 - 仮想AWSサーバーでCognitoの初期設定を行う
- ユーザープール作成
- ユーザー作成
- 仮想AWSサーバー(
-
Nextjs(App Router)
- ログインフォームの表示
-
aws-amplify
+@aws-amplify/ui-react
-
- 仮想Cognitoにログイン
- ログインフォームの表示
環境構築
mkdir local_nextjs_cognito
npx create-next-app@latest .
Nextjs の設定
Need to install the following packages:
create-next-app@15.3.2
Ok to proceed? (y)
√ Would you like to use TypeScript? ... No / Yes
√ Would you like to use ESLint? ... No / Yes
√ Would you like to use Tailwind CSS? ... No / Yes
√ Would you like your code inside a `src/` directory? ... No / Yes
√ Would you like to use App Router? (recommended) ... No / Yes
√ Would you like to use Turbopack for `next dev`? ... No / Yes
√ Would you like to customize the import alias (`@/*` by default)? ... No / Yes
√ What import alias would you like configured? ... @/*
フロントライブラリ追加
npm i aws-amplify @aws-amplify/ui-react
ライブラリのバージョンを掲載しておきます
package.json
"dependencies": {
"@aws-amplify/ui-react": "^6.11.2",
"aws-amplify": "^6.14.4",
"next": "15.3.2",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.3.2",
"typescript": "^5"
}
フォルダおよびファイルの作成
(ルートディレクトリで実行)
mkdir .\src\aws
New-Item .\src\aws\CognitoProvider.tsx
mkdir aws_mock
New-Item .\aws_mock\init.sh
New-Item .\aws_mock\Dockerfile
New-Item docker-compose.yml
Cognitoログイン画面の実装
今回は検証のため@aws-amplify/ui-react
で簡単に作ります
CognitoProvider.tsx
"use client";
import React from "react";
import { Amplify } from "aws-amplify";
import "@aws-amplify/ui-react/styles.css";
import { withAuthenticator } from "@aws-amplify/ui-react";
Amplify.configure(
{
Auth: {
Cognito: {
userPoolId: process.env.NEXT_PUBLIC_MOTO_USER_POOL_ID!,
userPoolClientId: process.env.NEXT_PUBLIC_MOTO_CLIENT_ID!,
userPoolEndpoint: process.env.NEXT_PUBLIC_MOTO_ENDPOINT,
},
},
},
{ ssr: true }
);
const CognitoProvider = ({ children }: { children: React.ReactNode }) => {
return <>{children}</>;
};
export default withAuthenticator(CognitoProvider);
layout.tsx
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import CognitoProvider from "@/aws/CognitoProvider"; // 追加
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ja"> {/**jaに変更 */}
<body className={`${geistSans.variable} ${geistMono.variable}`}>
<CognitoProvider>{children}</CognitoProvider> {/**追加 */}
</body>
</html>
);
}
aws_mockフォルダ
init.sh
の最後にパスワードを変更している理由:
Cognitoでユーザーを作成した際、メール認証が必要になります
モックサーバーのためメール送信ができません
メール認証を回避するためにパスワード変更を行っています
./aws_mock/Dockerfile
FROM alpine:3.19
WORKDIR /app
COPY init.sh .
RUN chmod +x init.sh
RUN apk --no-cache add curl jq
./aws_mock/init.sh
#!/bin/sh
# curlコマンドをインストールして使えるようにする
apk --no-cache add curl
# jqコマンドをインストールして使えるようにする
apk --no-cache add jq
# ユーザープールの作成
RESPONSE=$(curl -s -X POST http://moto:5000/ \
-H 'Content-Type: application/x-amz-json-1.1' \
-H 'X-Amz-Target: AWSCognitoIdentityProviderService.CreateUserPool' \
-H 'X-Amz-Date: 20240227T000000Z' \
-d '{
"PoolName": "MyTestUserPool",
"Policies": {
"PasswordPolicy": {
"MinimumLength": 8,
"RequireUppercase": true,
"RequireLowercase": true,
"RequireNumbers": true,
"RequireSymbols": true
},
"SignInPolicy": {
"AllowedFirstAuthFactors": [
"PASSWORD"
]
}
},
"UsernameAttributes": [
"email"
]
}')
# RESPONSEからUserPoolIDを取得する
USER_POOL_ID=$(echo $RESPONSE | jq -r '.UserPool.Id')
echo "User Pool ID: $USER_POOL_ID"
# UserPoolClientの作成
RESPONSE=$(curl -s -X POST http://moto:5000/ \
-H 'Content-Type: application/x-amz-json-1.1' \
-H 'X-Amz-Target: AWSCognitoIdentityProviderService.CreateUserPoolClient' \
-H 'X-Amz-Date: 20240227T000000Z' \
-d '{
"ClientName": "MyTestUserPoolClient",
"UserPoolId": "'"$USER_POOL_ID"'",
"GenerateSecret": false
}')
# RESPONSEからUserPoolClientIDを取得
USER_POOL_CLIENT_ID=$(echo $RESPONSE | jq -r '.UserPoolClient.ClientId')
echo "User Pool Client ID: $USER_POOL_CLIENT_ID"
# ユーザープールにユーザーを作成
RESPONSE=$(curl -s -X POST http://moto:5000/ \
-H 'Content-Type: application/x-amz-json-1.1' \
-H 'X-Amz-Target: AWSCognitoIdentityProviderService.AdminCreateUser' \
-H 'X-Amz-Date: 20240227T000000Z' \
-d '{
"UserPoolId": "'"$USER_POOL_ID"'",
"Username": "test123@example.com",
"TemporaryPassword": "Test@1234",
"UserAttributes": [
{
"Name": "email",
"Value": "test123@example.com"
},
{
"Name": "email_verified",
"Value": "true"
}
],
"MessageAction": "SUPPRESS"
}')
# RESPONSEからUserIDを取得
USER_ID=$(echo $RESPONSE | jq -r '.User.Username')
echo "User ID: $USER_ID"
# 抽出した各種IDを含む.env.localファイルを/appディレクトリ(ルートディレクトリ)に作成
cat <<EOF > /app/.env.local
NEXT_PUBLIC_MOTO_USER_POOL_ID=$USER_POOL_ID
NEXT_PUBLIC_MOTO_CLIENT_ID=$USER_POOL_CLIENT_ID
NEXT_PUBLIC_MOTO_ENDPOINT=http://127.0.0.1:5000
USER_ID=$USER_ID
USER_NAME=test123@example.com
USER_PASSWORD=Test@1234
EOF
echo ".env.local file created with the necessary environment variables in /app directory."
# ユーザーのパスワードを変更
RESPONSE=$(curl -s -X POST http://moto:5000/ \
-H 'Content-Type: application/x-amz-json-1.1' \
-H 'X-Amz-Target: AWSCognitoIdentityProviderService.AdminSetUserPassword' \
-H 'X-Amz-Date: 20240227T000000Z' \
-d '{
"UserPoolId": "'"$USER_POOL_ID"'",
"Username": "test123@example.com",
"Password": "Test@1234",
"Permanent": true
}')
echo "User password set to permanent for user: test123@example.com"
docker-compose.ymlの設定
appとしてフロントエンドの記載をしていますが、Dockerを使わずに起動させることもできます
※初回起動が遅いので、ローカル起動を推奨
docker-compose.yml
services:
moto:
image: motoserver/moto:latest
ports:
- "5000:5000"
command: >
-H 0.0.0.0
environment:
- MOTO_PORT=5000
aws_mock_init:
build:
context: ./aws_mock
volumes:
- .:/app
depends_on:
- moto
entrypoint: ["/bin/sh", "-c", "sleep 5 && ./aws_mock/init.sh"]
# フロントエンドをローカル起動するなら以下のappは不要です
app:
build:
context: .
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- WATCHPACK_POLLING=true
command: npm run dev
depends_on:
- moto
- aws_mock_init
Dockerで実行
VSCodeなどのエディターでRun All Service
実行(VSCodeの場合:拡張機能のDockerが必要)
一応コマンド例を掲載しておきます
#1. サービスのビルドと起動
docker-compose up --build
#2. バックグラウンド(デタッチド)で起動
docker-compose up -d
#3. サービスの停止
docker-compose down
#4. サービスの再ビルド
docker-compose build
#5. 特定サービスのみ起動(例: app)
docker-compose up moto
#6. ログの確認
docker-compose logs
#7. 特定サービスのログ確認(例: moto)
docker-compose logs moto
Dockerでmoto
サーバーが起動している状態で、aws_mock_init
を実行すると、
.env.local
ファイル内に仮想環境のCognito接続用の各種IDが記載されます
ログイン用のIDとパスワードも記載してありますので、検証時にお使いください