nuxt logo

ドキュメント翻訳(非公式)

Nuxt.js
Version:v3.17

セッションと認証

認証はウェブアプリで非常に一般的な要件です。このレシピでは、Nuxtアプリで基本的なユーザー登録と認証を実装する方法を紹介します。

はじめに

このレシピでは、Nuxt Auth Utilsを使用してフルスタックのNuxtアプリで認証を設定します。このモジュールは、クライアントサイドとサーバーサイドのセッションデータを管理するための便利なユーティリティを提供します。

このモジュールはセッションデータを保存するためにセキュアでシールドされたクッキーを使用するため、セッションデータを保存するためのデータベースを設定する必要はありません。

nuxt-auth-utilsのインストール

nuxt CLIを使用してnuxt-auth-utilsモジュールをインストールします。

Terminal
npx nuxt module add auth-utils

このコマンドはnuxt-auth-utilsを依存関係としてインストールし、nuxt.config.tsmodulesセクションに追加します。

クッキー暗号化キー

nuxt-auth-utilsはシールドされたクッキーを使用してセッションデータを保存するため、セッションクッキーはNUXT_SESSION_PASSWORD環境変数からの秘密キーを使用して暗号化されます。

設定されていない場合、この環境変数は開発モードで実行中に自動的に.envに追加されます。

.env
NUXT_SESSION_PASSWORD=a-random-password-with-at-least-32-characters

デプロイ前にこの環境変数を本番環境に追加する必要があります。

ログインAPIルート

このレシピでは、静的データに基づいてユーザーをサインインするためのシンプルなAPIルートを作成します。

メールアドレスとパスワードをリクエストボディに含むPOSTリクエストを受け入れる/api/login APIルートを作成しましょう。

server/api/login.post.ts
import { z } from 'zod'

const bodySchema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
})

export default defineEventHandler(async (event) => {
  const { email, password } = await readValidatedBody(event, bodySchema.parse)

  if (email === 'admin@admin.com' && password === 'iamtheadmin') {
    // クッキーにユーザーセッションを設定
    // このサーバーユーティリティはauth-utilsモジュールによって自動インポートされます
    await setUserSession(event, {
      user: {
        name: 'John Doe'
      }
    })
    return {}
  }
  throw createError({
    statusCode: 401,
    message: 'Bad credentials'
  })
})

プロジェクトにzod依存関係をインストールすることを忘れないでください(npm i zod)。

nuxt-auth-utilsによって公開されているsetUserSessionサーバーヘルパーについてもっと読む。

ログインページ

このモジュールは、アプリケーション内でユーザーが認証されているかどうかを知るためのVueコンポーザブルを公開しています。

const { loggedIn, session, user, clear, fetch } = useUserSession()

/api/loginルートにログインデータを送信するフォームを持つログインページを作成しましょう。

pages/login.vue
<script setup lang="ts">
const { loggedIn, user, fetch: refreshSession } = useUserSession()
const credentials = reactive({
  email: '',
  password: '',
})
async function login() {
  $fetch('/api/login', {
    method: 'POST',
    body: credentials
  })
  .then(async () => {
    // クライアントサイドでセッションを更新し、ホームページにリダイレクト
    await refreshSession()
    await navigateTo('/')
  })
  .catch(() => alert('Bad credentials'))
}
</script>

<template>
  <form @submit.prevent="login">
    <input v-model="credentials.email" type="email" placeholder="Email" />
    <input v-model="credentials.password" type="password" placeholder="Password" />
    <button type="submit">Login</button>
  </form>
</template>

APIルートの保護

サーバールートを保護することは、データを安全に保つための鍵です。クライアントサイドのミドルウェアはユーザーにとって便利ですが、サーバーサイドの保護がなければデータにアクセスされる可能性があります。機密データを含むルートを保護することは重要であり、ユーザーがログインしていない場合は401エラーを返すべきです。

auth-utilsモジュールは、ユーザーがログインしてアクティブなセッションを持っていることを確認するためのrequireUserSessionユーティリティ関数を提供します。

認証されたユーザーのみがアクセスできる/api/user/statsルートの例を作成しましょう。

server/api/user/stats.get.ts
export default defineEventHandler(async (event) => {
  // ユーザーがログインしていることを確認
  // 有効なユーザーセッションからのリクエストでない場合、401エラーをスローします
  const { user } = await requireUserSession(event)

  // TODO: ユーザーに基づいていくつかの統計を取得

  return {}
});

アプリルートの保護

サーバーサイドルートがあることでデータは安全ですが、何もしなければ、認証されていないユーザーが/usersページにアクセスしようとすると奇妙なデータを取得する可能性があります。クライアントサイドでルートを保護し、ユーザーをログインページにリダイレクトするためのクライアントサイドミドルウェアを作成する必要があります。

nuxt-auth-utilsは、ユーザーがログインしているかどうかを確認し、ログインしていない場合にリダイレクトするための便利なuseUserSessionコンポーザブルを提供します。

/middlewareディレクトリにミドルウェアを作成します。サーバーとは異なり、クライアントサイドのミドルウェアはすべてのエンドポイントに自動的に適用されるわけではなく、適用したい場所を指定する必要があります。

middleware/authenticated.ts
export default defineNuxtRouteMiddleware(() => {
  const { loggedIn } = useUserSession()

  // 認証されていない場合、ユーザーをログイン画面にリダイレクト
  if (!loggedIn.value) {
    return navigateTo('/login')
  }
})

ホームページ

ルートを保護するためのアプリミドルウェアができたので、認証されたユーザー情報を表示するホームページで使用できます。ユーザーが認証されていない場合、ログインページにリダイレクトされます。

保護したいルートにミドルウェアを適用するためにdefinePageMetaを使用します。

pages/index.vue
<script setup lang="ts">
definePageMeta({
  middleware: ['authenticated'],
})
  
const { user, clear: clearSession } = useUserSession()

async function logout() {
  await clearSession()
  await navigateTo('/login')
}
</script>

<template>
  <div>
    <h1>Welcome {{ user.name }}</h1>
    <button @click="logout">Logout</button>
  </div>
</template>

また、セッションをクリアしてログインページにリダイレクトするためのログアウトボタンも追加しました。

結論

Nuxtアプリで非常に基本的なユーザー認証とセッション管理を設定することに成功しました。また、認証されたユーザーのみがアクセスできるように、サーバーとクライアントサイドで機密ルートを保護しました。

次のステップとして、以下を行うことができます:

OAuth認証、データベース、CRUD操作を備えたNuxtアプリの完全な例については、オープンソースのatidoneリポジトリをチェックしてください。