LoginSignup
60
66

Next.jsとAWSで認証つきサイトを爆速でホストする(Next.js + Cognito + S3 + Cloudfront)

Last updated at Posted at 2023-12-20

はじめに

NRI OpenStandia Advent Calendar 2023の21日目は Next.jsとAWSで認証付きサイトを爆速でホストする方法を紹介いたします!
趣旨としては、真面目にやると大変な認証のバックエンドもフロントエンドもCognitoに任せて、簡単に認証付きサイトホストしてしまおう!ということです。
今回はNext.jsプロジェクトをStatic ExportsしたものをS3 + CloudFrontでホスティングすることで、パブリックにアクセス可能なWebページを構築します。

本記事のゴール

  • Next.jsで作成したWebアクセス可能な認証つきサイトをホスティングすること
  • Topページにアクセスした際、未ログインなら認証が求められ、ログイン成功後Topページが閲覧可能になること

使用するもの

  • 開発フレームワーク:Next.js (v14.0.4) App Router
  • 認証:AWS Cognito
  • Webサイトホスティング:AWS S3 + AWS CloudFront

1. Next.jsの環境構築

1.1 Node.jsとnpmのインストール

Node.jsのダウンロードページからインストーラをダウンロードします。
インストーラを起動しインストール完了後、ターミナルで以下を実行し、インストールできているか確認します。
正しくインストールされていれば、Node.jsとnpmそれぞれのバージョンが表示されます。

node -v
> v20.0.9
npm -v
> 10.2.1

Tips (本筋とは関係ないですが...)
VoltaのようなNode.jsバージョン管理ツールを使用すると、自由にNode.jsのバージョンを切り替えられてオススメ! (参考)

1.2 ローカルにNext.jsのプロジェクト作成

プロジェクトを作成したい任意のディレクトリ上で以下を実行します。

npx create-next-app@latest

表示される質問に答えて構築を完了します。
ここで表示される各質問についてはcreate-next-appで訊かれていることを参考にしてください。

> What is your project named? my-app
> 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 to use `src/` directory? No / Yes
> Would you like to use App Router? (recommended) No / Yes
> Would you like to customize the default import alias (@/*)? No / Yes
> What import alias would you like configured? @/*

作成されたディレクトリに移動してlocalhostを起動します。

npm run dev

localhost:3000にアクセスしてページが表示されていればNext.jsの環境構築はOKです。
image.png

2. ログイン画面を作成

ここで目指すゴールは、先ほどのTop画面にアクセスした際ログインがまだであれば、ログイン画面が表示されることです。
AWSにはAWS Amplifyという、モバイルアプリやWebアプリの開発を迅速化するためのフルスタックの開発フレームワークサービスが存在します。
Amplifyを使用するとAmplify経由でS3のホスティングができたりするのですが、今回はS3とCloudFrontを自前で用意するためAmplifyそのものは使わず、Amplifyのライブラリに含まれるCognitoとの連携パーツだけを使用します。

2.1 Next.js側の準備

Amplifyのライブラリをインストールします。(本記事は2023年12月時点で最新のv6.0.7)

npm install @aws-amplify/ui-react aws-amplify

src/app/layout.tsx@aws-amplify/ui-react/styles.cssのimportし、Amplifyで用意されているログイン画面のstyleをimportします。

src/app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import {Amplify} from 'aws-amplify'
import './globals.css'
+import '@aws-amplify/ui-react/styles.css';

次にTopページsrc/app/page.tsxに認証を追加します。

src/app/page.tsx
+'use client'
+
+import { withAuthenticator } from "@aws-amplify/ui-react";
import Image from 'next/image'
import styles from './page.module.css'

- export default function Home() {
+ function Home() {
  return (
    <main className={styles.main}>
        <div className={styles.description}>
            <p>中略...</p>
        </div>
    </main>
  )
}
+export default withAuthenticator(Home)

export default withAuthenticator(Home)のようにexport default記述時にコンポーネントをwithAuthenticatorでラップすることで、認証が求められるようになります。
Topページ以外のページについてもwithAuthenticatorでラップすることで同様に認証を求めることができます。
ここで再度localhost:3000にアクセスしてみましょう。
すると、先ほどと違い認証が求められるようになっていますね!
image.png
しかし、まだAWS側でCognitoの設定をしていないためログインはできません。

Note
ログイン画面のカスタマイズ方法はこちらをご参照ください。

2.2 AWS Cognitoでユーザを作成

AWS CognitoはAWS上に認証システムが構築されており、サーバレスに認証を実装することができるサービスです。

Cognitoの設定方法の詳細についてはAWS公式Cognitoチュートリアルをご参照ください。

最初に「ユーザープールを作成」をクリックし、ユーザープールの作成を行います。
image.png
ユーザープールとは、ウェブおよびモバイルアプリケーションの認証と承認のためのユーザーディレクトリを指し、このプールに各アカウントが追加されていくことになります。
画面に従ってユーザープールの作成を進め、「Step5:アプリケーションを統合 」のアプリケーションクライアントは「パブリッククライアント」を選択します。
ユーザープールの作成が完了したら、作成したユーザープールに移動し「ユーザーの作成」からユーザーを追加します
image.png
今回はユーザー名がadminのユーザーを作成しました。

2.3 Next.jsとCogintoを連携させる

src/app/page.tsxAmplify.configureを追加し、userPoolClientIduserPoolIdの情報を入力します。
userPoolClientIdはAWS上の該当ユーザープールページの下部「アプリケーションクライアントのリスト」に記載されており、userPoolIdは同ページ上部の「ユーザープールの概要」に記載があります.

src/app/page.tsx
'use client'
+import {Amplify} from 'aws-amplify'
import { withAuthenticator } from "@aws-amplify/ui-react";
import Image from 'next/image'
import styles from './page.module.css'

+Amplify.configure({
+ Auth: {
+   Cognito: {
+     userPoolClientId: '1234567abcdefg',
+     userPoolId: 'ap-northeast-1_ABCDEFG',
+  }
+ }
+})

function Home() {
  return (
    <main className={styles.main}>
        <div className={styles.description}>
            <p>中略...</p>
        </div>
    </main>
  )
}
export default withAuthenticator(Home)

Attention
amplifyライブラリv6から過去とconfigureの設定方法が違うようです。本記事では公式リファレンスを参照しています。(2023年12月時点)

以上の変更により、Cognitoで作成したadminユーザーでサインインできるようになりました!
※初回サインイン時はパスワードの変更を求められます。
ここまでで、ローカル上でCoginitoによる認証付きのNext.jsプロジェクトを作成することができました。

3. Next.jsプロジェクトをAWSでホスティング

ローカル環境で認証付きのNext.jsプロジェクトができたので、続いてAWSでホスティングを行います。

3.1 完成したプロジェクトのbuild

通常、Next.jsの実行にはNode.jsのランタイムが必要ですが、今回はS3 + CloudFrontでのWebサイトホスティングを目的としているので、Next.jsプロジェクトをStatic Exportsで静的ファイルとして出力します。
next.config.jsを以下に変更します。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
+   output: 'export',
+   trailingSlash: true,
}

module.exports = nextConfig
  • output:buildした際にoutディレクトリに出力を行う ※Next.js v13.3以降はこの方法
  • trailingSlash/aboutのようなアクセスに対して、/about/idex.htmlにリダイレクトしてくれるようになる

ターミナルでbuildしてS3にアップロードするファイルを出力します。

npm run build

ファイルはデフォルトでoutディレクトリに出力されます。

3.2 AWS S3を作成

続いてAWS側の構築を進めます。
基本的にデフォルトの設定のままバケットを作成します。
今回はクライアントからアクセスを受けるのはCloudFrontなので、「パブリックアクセス」は全てブロック、「静的サイトホスティング」も無効で良いです。
image.png
S3バケットの作成が完了したら、先ほどのbuildで作成されたoutディレクトリの全てのファイルをS3バケットにアップロードします。

3.3 CloudFrontを作成

最後にクライアントからアクセスを受けるCloudFrontを作成します。
「ディストリビューションを作成」でディストリビューションを作成します。
オリジンドメインには先ほど作成したS3バケットを選択し、「オリジンパス」はindex.htmlとします。
「オリジンアクセス」は「Origin access control settings (recommended)」を選択し、「Origin access control」は新規に作成します。
その他の項目についてはデフォルトで良いです。
ディストリビューション作成後、先ほど作成したS3バケットのバケットポリシーを変更します。
作成したディストリビューションの「オリジン」タブからオリジンを編集し、編集画面内のバケットポリシーをコピーします。
image.png
「S3バケットアクセス許可に移動」からS3のアクセス許可画面に遷移し、バケットポリシーをコピーしたものに変更します。
ここまでで全ての構築が完了しました!

Note
もしTopページ以外のページも作成していて、遷移したい場合はCloudFrontの「エラーページ」設定が必要になります。詳細はこちらをご参照ください。

4. 実際にアクセスできるか確認

最後に認証付きサイトがホスティングできているか確認しましょう!
作成したCloudFrontのディストリビューションに記載されている「ディストリビューションドメイン名」にアクセスすると、サイトにアクセスすることができるはずです。
初回アクセス時に先ほどの認証画面が表示されて、認証情報入力→ログイン 後にTopページが表示されていれば成功です!
image.gif
ここまでで認証付きサイトが無事ホスティングされていることを確認できました。

おわりに

今回はNext.jsとAWSで認証付きサイトをホスティングする方法を紹介しました。
Cognitoが認証部分を担ってくれているのと、AmplifyライブラリのCognito連携と画面部品を使用することで、簡単に認証付きサイトをホスティングできたのではないでしょうか?
CognitoはGoogleログインなど他サービスの認証プロバイダーにも対応しており、リッチな認証を簡単に実装できるのが嬉しいですね。

参考

60
66
1

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
60
66