AWS Amplify + Cognito + Next.jsで認証付きページ作る

AWS, amplify, cognito, Next.js
2021-06-14

AWS Amplify + Cognito + Next.jsで認証付きページ(ログインが必要なページ)を作る方法です。

モチベ

やりたいこと

  • とあるプロダクトの管理画面を作りたい
  • 管理画面はプロダクトサイトとは別の場所(ドメイン)で作成し、プロダクトサイトと切り離す。
  • 管理ユーザ用のテーブルは作りたくない
  • 認証機能を0から作るのは面倒なので、Cognitoの認証機能を利用したい。(UIも含め)
  • データソースはプロダクトサイトと共通のものを利用することになる。
  • 画面とデータソースをつなぐAPI自体は管理画面用に作成する(本来はここも切り離したいが)

上記のような要件を満たしたいたいため、 画面側をAmplify(frontent) + Next.jsで作成し、認証機能をAmplifyのAuthenticationを使い、認証ユーザ(管理ユーザ)のデータをCoginitoで管理するようにしました。

Amplify とは

AWS Amplifyとはなにかと一言で説明するのは難しいのですが、自分が思うのはAmplifyはインターフェイスみたいなもので、裏側ではAWSの各種サービスを組み合わせ、オーケストレーションしているサービスみたいなものかなと思います。 Amplifyから利用されるサービスはIAM、Lambda、CloudFormation、Cognito、AppSyncなどがあります。できることは結構多いです(そして覚えることも)。

Amplify Framework

主な Frameworkには例として、以下のものがあります

  • Amplify CLI ... バックエンド機能のシンプルなCLI機能を提供
  • Amplify Libraries ... ユースケースを中心としたクライアントライブラリで、宣言的なインターフェイスを実装することでバックエンド使えるようにする
  • Amplify UI Components ... React, Vue, RNなどのUIライブラリ
  • Amplify Console ... AWSのサービスでgitベースのワークフロー、継続的なデプロイ、ホスティングなどクラウドを使ったフルスタックな機能を提供。(CLIで操作できる内容と同じ)

Amplifyをインストール

ローカル環境に、npmを利用して、Amplify CLIをインストールします。

npm install -g @aws-amplify/cli

Amplifyの初期設定を行う

Amplify CLIの初期設定として、デプロイを行うユーザ(IAM)を作成し、アクセスキーを登録します。 ※ 詳細はこちらのビデオを参照、https://youtu.be/fWbM5DLh25U

amplify configure

Next.jsのアプリを作成

ひとまず、ローカルで動作するNext.jsの環境を作ります。

こちらの記事のような、プレーンなNext.jsでもよいですし、create-next-appでもいいです。

⚠️
ただし、Next.jsのバージョンはv9系もしくはv10.2.0としてください。それ以上のバージョンではAmplify上でnext.jsのAPI routesが動きません。(2021/06/14現在)

Amplifyのbackend serviceを作成

Amplifyのbackend機能は、notifications, analytics, apiなど多数の機能を選択して利用することができます。今回はAuthenticationだけ利用したいのでそれを追加します。

プロジェクトのAmplifyを定義するため、ルートディレクトリで以下を実行します。

amplify init

基本的にはデフォルトで良いですが、以下の点を変えます。

  • Project Nameは固有のもの(記号は使えない、大文字小文字は区別できる)
  • Next.jsを利用するのであれば、Distribution Directory Pathを .next とします
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project nextamplified
The following configuration will be applied:

Project information
| Name: nextamplified
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react
| Source Directory Path: src
| Distribution Directory Path: .next
| Build Command: npm run-script build
| Start Command: npm run-script start

initが行われるとローカルの環境に、

  • amplify というディレクトリが作成され、そこにバックエンドをのスタックを定義するためのコードが追加されていく。
  • src ディレクトリに aws-exports.jsというファイルが作成され、amplifyで作成したサービスの設定を保持する。これによりamplifyクライアントがバックエンドサービスの情報を取得することができる。Amplify CLIを使ってカテゴリーを追加・削除したり、バックエンドの設定を更新すると、aws-exports.jsの設定が自動的に更新されます。
  • .gitignore にamplifyで追加されたファイルの中でコミットが不要なものが追加される

また、AWS Amplifyにプロジェクトが作成され、そのbackendに dev という環境が作成されます。 その際、自動で作成されるAWS側のサービスとして

  • AWS CloudFormationに amplify-nextamplified-dev-xxx のようなオーケストレーションの設定
  • S3に amplify-nextamplified-dev-xxx-deploymentバケット(amplifyの設定ファイルを保持)
  • IAM Roleに認証ユーザ用のそれぞれのロールができる(後述のauthのためのロールと思われる)
    • amplify-nextamplified-dev-xx-authRole,
    • amplify-nextamplified-dev-xx-unauthRole

CloudFormationのログをみると以下のようになっているので、おそらくAmplifyがcloudformationをキックして各種サービス生成するという流れなのかなと思います。

An image from Notion

AmplifyのAuthを追加

Amplify環境ができたので次に認証機能を追加します。

amplify add auth

Cognitoの設定を聞かれるので、回答していきます。 今回はEmailでのログインを行いたいのでそのように設定します。

Using service: Cognito, provided by: awscloudformation

 The current configured provider is Amazon Cognito.

 Do you want to use the default authentication and security configuration? Default configuration
 Warning: you will not be able to edit these selections.
 How do you want users to be able to sign in? Email
 Do you want to configure advanced settings? No, I am done.
Successfully added auth resource xyzaadminb16d7f70 locally

バックエンドのデプロイ

設定ができたら、pushコマンドでデプロイを行います。

amplify push

Authの設定がAmplify上に追加されます

✔ Successfully pulled backend environment dev from the cloud.

Current Environment: dev

| Category | Resource name         | Operation | Provider plugin   |
| -------- | --------------------- | --------- | ----------------- |
| Auth     | nextamplifiedcxxxxxxx | Create    | awscloudformation |

実行すると以下のサービスにamplify用の設定が追加されます

  • Cognitoのユーザプール
    • Authを設定した場合に、nextamplifiedxx_userpool_xx-dev のようなユーザプールが作成される
  • Role
    • lambda, cogniteそれぞれのサービスロールができる
  • lambda
    • amplify-nextamplified-dev-UpdateRolesWithIDPFuncti-XXXX
    • amplify-nextamplified-dev-105-UserPoolClientLambda-XXXX
    • 及び、そのlambdaが実行されたログがCloudWatchに作られる

フロント側に認証機能を追加する

backendがデプロイされたので、今度はフロント側に認証機能を呼び出す処理を追加します。

Amplify librariesのインストール

Amplify用のjsライブラリをインストールします。今回は以下の2つを利用します。

npm install aws-amplify @aws-amplify/ui-react
  • aws-amplify ... 作成されたアプリケーションでAmplifyを動かすためのメインライブラリ
  • @aws-amplify/ui-react ... Reactで構成されたアプリケーションを構築するためのUIコンポーネント

認証機能のコンポーネントを追加

index.tsxを以下のようにします

import { Amplify } from 'aws-amplify';
import { NextPage } from 'next';
import React from 'react';

import { AmplifyAuthenticator } from '@aws-amplify/ui-react';

import awsExports from '../aws-exports';

Amplify.configure({ ...awsExports });

const Index: NextPage<{}> = () => {
  return (
    <AmplifyAuthenticator>
      <div>ようこそ</div>
    </AmplifyAuthenticator>
  )
};

export default Index;

保存し、localhost:3000にアクセスすると、初回はログインしていないので、ログイン画面が表示されます。

An image from Notion

サインアップを非表示にする

今回はサインアップを行わないので、<AmplifyAuthenticator>内のslot AmplifySignIn にhideSignUpを追加します。

<AmplifyAuthenticator>
  <AmplifySignIn slot="sign-in" hideSignUp />
</AmplifyAuthenticator>

ログインユーザを登録

AWSのコンソールからCognito画面を呼び出し、その中でユーザを登録します。 ユーザ名がemailとなるよう設定したので、usernameはメールアドレスで指定します。

An image from Notion
Cognito上でのユーザの追加

ログインが行われ認証されたユーザのみUIが表示されるようになりました。

An image from Notion

frontendのデプロイ

ローカルで認証機能の確認できたので、Amplifyにdeployをします。プロジェクトのgitを作成し、github等のリモートホストにpushします。

Amplify hostingを追加

Next.jsのSSRを利用するため、hostingを追加します。

amplify add hosting
? Select the plugin module to execute Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
? Choose a type Continuous deployment (Git-based deployments)
? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your repository

コンソールが開くのでfrontendタブから該当するgitのリモート先を選択し、設定します。 設定が完了するとビルドが実行されるので完了するのを待ちます。

このときにデプロイ先のCloudFront、S3が作られます。

An image from Notion

デプロイ完了後、作成されたURL https://main.xx.amplifyapp.comにアクセスすると画面が表示されます。

以上まずログインができるところまでを書きました。実際にcognitoのユーザが正しいかなどは後で書きます。

その他 tipsなど

サーバ上でNext.js /apiが動かない

上に書いたとおり、2021/06/14現在最新のNext.jsのバージョンはv10.2.3、現状Amplifyがサポートしているのがv9であり10.2.0より上のバージョンだとLambda Edgeがエラーになるようで、Cloudfrontのエラーがでて動かないです。 https://github.com/aws-amplify/amplify-console/issues/1915 オフィシャルのドキュメントでは以下のように書かれています。

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/server-side-rendering-amplify.html

Your Next.js app uses unsupported features You can deploy an app created with Next.js version 10. However, Amplify doesn't currently support the full feature set. Amplify supports all features of Next.js versions 9.x.x, except for Incremental Static Regeneration (ISR).

Amplifyのアプリを削除する場合

コンソールから削除を選択した場合ローカル環境のamplifyディレクトリが残ってしまうので、以下のコマンドで削除するほうがよいです。

amplify delete
Written by Kyohei Tsukuda who lives and works in Tokyo 🇯🇵 , building useful things 🔧.