初めに
仕事で認証系を実装することになったが、cognito等を使って外に出した方が実装コストや保守運用も楽になるので、簡単な実装ガイドとして本記事を書く
コードは以下のリポジトリ
準備
AWS Cognito
まず、認証用のユーザープールをaws cognitoで作成する必要がある。
Amazon Cognito > ユーザープール > ユーザープールを作成
ユーザープールの作成後に Cognito ユーザープールのサインインオプションを変更することはできません。
cognito関連の設定は変更が効かないので、慎重に。
今回はメールアドレスとパスワードのみのシンプルな認証なので以下で設定
認証プロバイダー
プロバイダータイプ:Cognito ユーザープール
Cognito ユーザープールのサインインオプション:Eメール
パスワードポリシー
パスワードポリシーモード:Cognito のデフォルト
多要素認証
MFA の強制:MFAなし(本当は必要だよ)
ユーザーアカウントの復旧
セルフサービスのアカウントの復旧情報:セルフサービスのアカウントの復旧を有効化 - 推奨
ユーザーアカウント復旧メッセージの配信方法:Eメールのみ
サインアップエクスペリエンスを設定
セルフサービスのサインアップ:自己登録を有効化
属性検証とユーザーアカウントの確認
検証する属性: E メールのメッセージを送信、E メールアドレスを検証
属性変更の確認: 未完了の更新があるときに元の属性値をアクティブに保つ - 推奨
未完了の更新があるときのアクティブな属性値: E メールアドレス
追加の必須属性: 無し
メッセージ配信を設定
E メール: Cognito で E メールを送信
ユーザープール名: 任意
ホストされた認証ページ: 無効
アプリケーションタイプ: パブリッククライアント
アプリケーションクライアント名: 任意
クライアントシークレット: クライアントのシークレットを生成しない
ユーザープールIDとクライアントIDを保存しておく
コード
何はともあれgit clone
git clone https://github.com/sandy-sunday/nuxt3_cognito_tutorial.git
環境変数のテンプレートをコピーして、先ほど保存したユーザープールIDとクライアントIDをコピぺする。
cp .env.example .env
NUXT_PUBLIC_USER_POOL_ID=your_user_pool_id
NUXT_PUBLIC_CLIENT_ID=your_client_id
必要パッケージをインストールしてサーバーを起動
yarn install
yarn dev
localhost:3000
にアクセスして画面が表示されたら成功。
コード補足
cognitoで作ったユーザーでログインできない
実装時に詰まった部分として、cognitoのコンソール上で作成したユーザーで初めてログインしようとしたら、"Error: New password is required."と出てログインに失敗することがあった。この状況でcognitoUser.forgotPassword()
を使っても、認証コードが送られてくることは無く、cognitoコンソール上で「E メールアドレスを検証済みとしてマークする」にチェックを入れても解消されることは無かった。
どうやら初回ログインのみcognitoUser.completeNewPasswordChallenge()
でパスワードを設定する必要がある。
// /pages/login.ts
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function() {
window.location.href = '/login-success';
},
newPasswordRequired: function(userAttributes, requiredAttributes) {
showNewPasswordInput.value = true;
buttonLabel.value = 'Reset Password';
// On initial login, the user must change their password
cognitoUser.completeNewPasswordChallenge(newPassword.value, {}, {
onSuccess: function() {
window.location.href = '/login-success';
},
onFailure: function(err) {
console.log("Error:", err);
}
});
},
onFailure: function(err) {
console.log("Error:", err);
}
});
global is not defined
cognito 関連の設定は/plugins/cognito.ts
に実装している。プラグインとして、各ページで利用できるようにしているのだが、JavaScriptのグローバルオブジェクトは、ブラウザ上とNode.js上では異なり、ブラウザ上では”window”、Node.js上では”global”が対応するため、yarn dev
で実行しようとすると500 global is not defined
と出てしまう。
// /nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true },
vite: {
define: {
'window.global': {}, // In SSR, window is not defined. This is a workaround.
},
},
.....
...
対策として、globalに空オブジェクトを定義してあげるとエラーを回避できる。詳しくは下の記事を参照
環境変数の設定
// /nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
userPoolId: '',
clientId: '',
}
},
});
.env
を用意して環境変数に指定する方法を忘れていたため、記載。NUXT_PUBLIC_USER_POOL_ID
のように接頭にNUXTを付けると環境変数として認知される。続けてPUBLIC
のようにネストすることも可能。nuxt3からはdotenvがプリインストールされているようで設定が楽になってる。
ログインにリダイレクト
// /middleware/redirect-login.ts
export default defineNuxtRouteMiddleware((to,from) => {
return navigateTo('/login')
})
<!-- /pages/index.vue -->
<template>
<h1>Landing Page</h1>
</template>
<script setup lang="ts">
definePageMeta({
middleware: ['redirect-login'] // redirecting to login page if not logged in
})
</script>
デフォルトのランディングページであるindex.vue
はログイン画面にリダイレクトするよう設定した。実際のWebサービスでは認証トークンに有効期限を設定して、有効期限が切れたらログインないしトップページに戻す為、先行実装。