はじめに
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
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です。
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します。
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
に認証を追加します。
+'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にアクセスしてみましょう。
すると、先ほどと違い認証が求められるようになっていますね!
しかし、まだAWS側でCognitoの設定をしていないためログインはできません。
Note
ログイン画面のカスタマイズ方法はこちらをご参照ください。
- 日本語化&文言変更:AmplifyでCognitoの認証画面をカスタマイズする(React)
- その他詳細なデザイン変更(ヘッダーフッターなど):Amplify Authenticator Customization
- 設定変更(サインインのみなど):Amplify Authenticator Configuration
2.2 AWS Cognitoでユーザを作成
AWS CognitoはAWS上に認証システムが構築されており、サーバレスに認証を実装することができるサービスです。
Cognitoの設定方法の詳細についてはAWS公式Cognitoチュートリアルをご参照ください。
最初に「ユーザープールを作成」をクリックし、ユーザープールの作成を行います。
ユーザープールとは、ウェブおよびモバイルアプリケーションの認証と承認のためのユーザーディレクトリを指し、このプールに各アカウントが追加されていくことになります。
画面に従ってユーザープールの作成を進め、「Step5:アプリケーションを統合 」のアプリケーションクライアントは「パブリッククライアント」を選択します。
ユーザープールの作成が完了したら、作成したユーザープールに移動し「ユーザーの作成」からユーザーを追加します
今回はユーザー名がadminのユーザーを作成しました。
2.3 Next.jsとCogintoを連携させる
src/app/page.tsx
にAmplify.configure
を追加し、userPoolClientId
とuserPoolId
の情報を入力します。
userPoolClientId
はAWS上の該当ユーザープールページの下部「アプリケーションクライアントのリスト」に記載されており、userPoolId
は同ページ上部の「ユーザープールの概要」に記載があります.
'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
を以下に変更します。
/** @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なので、「パブリックアクセス」は全てブロック、「静的サイトホスティング」も無効で良いです。
S3バケットの作成が完了したら、先ほどのbuildで作成されたoutディレクトリの全てのファイルをS3バケットにアップロードします。
3.3 CloudFrontを作成
最後にクライアントからアクセスを受けるCloudFrontを作成します。
「ディストリビューションを作成」でディストリビューションを作成します。
オリジンドメインには先ほど作成したS3バケットを選択し、「オリジンパス」はindex.html
とします。
「オリジンアクセス」は「Origin access control settings (recommended)」を選択し、「Origin access control」は新規に作成します。
その他の項目についてはデフォルトで良いです。
ディストリビューション作成後、先ほど作成したS3バケットのバケットポリシーを変更します。
作成したディストリビューションの「オリジン」タブからオリジンを編集し、編集画面内のバケットポリシーをコピーします。
「S3バケットアクセス許可に移動」からS3のアクセス許可画面に遷移し、バケットポリシーをコピーしたものに変更します。
ここまでで全ての構築が完了しました!
Note
もしTopページ以外のページも作成していて、遷移したい場合はCloudFrontの「エラーページ」設定が必要になります。詳細はこちらをご参照ください。
4. 実際にアクセスできるか確認
最後に認証付きサイトがホスティングできているか確認しましょう!
作成したCloudFrontのディストリビューションに記載されている「ディストリビューションドメイン名」にアクセスすると、サイトにアクセスすることができるはずです。
初回アクセス時に先ほどの認証画面が表示されて、認証情報入力→ログイン 後にTopページが表示されていれば成功です!
ここまでで認証付きサイトが無事ホスティングされていることを確認できました。
おわりに
今回はNext.jsとAWSで認証付きサイトをホスティングする方法を紹介しました。
Cognitoが認証部分を担ってくれているのと、AmplifyライブラリのCognito連携と画面部品を使用することで、簡単に認証付きサイトをホスティングできたのではないでしょうか?
CognitoはGoogleログインなど他サービスの認証プロバイダーにも対応しており、リッチな認証を簡単に実装できるのが嬉しいですね。