Skip to content

認証の実装

公開日:December 10, 2024更新日:December 10, 2024
NextjsTypeScriptCoding📄

この章では、Next.jsアプリケーションに認証機能を実装する方法について学びます。認証とは、ユーザーが本人であることを確認するプロセスです。ここでは、認証の基本的な概念、認証方法の種類、そしてNext.jsアプリケーションに認証を実装する具体的な手順を解説します。

1. 認証とは

認証は、ユーザーが本人であることを確認するためのセキュリティ対策です。Webアプリケーションでは、ユーザー名とパスワードを使った認証が一般的ですが、他にも様々な認証方法があります。

認証の目的

認証の主な目的は、以下の通りです。

  • ユーザーの本人確認: リソースへのアクセスを許可する前に、ユーザーが本人であることを確認する。
  • 不正アクセスの防止: 許可されていないユーザーが、アプリケーションのリソースにアクセスするのを防ぐ。
  • セキュリティの向上: ユーザーデータを保護し、アプリケーション全体のセキュリティを向上させる。

認証情報の管理

認証を実装する際には、ユーザーの認証情報(クレデンシャル)を安全に管理することが重要です。パスワードなどの機密情報は、ハッシュ化してデータベースに保存する必要があります。また、セッション管理を適切に行い、不正アクセスを防ぐ必要があります。

2. 主な認証方法

Webアプリケーションで使用される主な認証方法には、以下のようなものがあります。

セッションベース認証

サーバー側でセッションを管理し、クライアントとサーバー間でセッションIDをやり取りする認証方法です。

  1. ユーザーがログイン情報を送信する。
  2. サーバーはログイン情報を検証し、セッションIDを生成してセッション情報をサーバー側に保存する。
  3. サーバーはセッションIDをCookieなどに保存してクライアントに返す。
  4. クライアントは以降のリクエストにセッションIDを含めて送信する。
  5. サーバーはリクエストに含まれるセッションIDを検証し、対応するセッション情報を取得して認証を行う。

トークンベース認証

サーバー側でトークン(JWTなど)を生成し、クライアントに渡す認証方法です。クライアントは、以降のリクエストにトークンを含めて送信します。

  1. ユーザーがログイン情報を送信する。
  2. サーバーはログイン情報を検証し、トークンを生成する。
  3. サーバーはトークンをクライアントに返す。
  4. クライアントは以降のリクエストのAuthorizationヘッダーなどにトークンを含めて送信する。
  5. サーバーはリクエストに含まれるトークンを検証して認証を行う。

OAuth

外部の認証サービス(Google、Facebook、Twitterなど)を利用して認証を行う方法です。

  1. ユーザーが外部サービスの認証ページにリダイレクトされる。
  2. ユーザーが外部サービスで認証を行う。
  3. 外部サービスがユーザーをアプリケーションにリダイレクトする。
  4. アプリケーションは外部サービスからユーザー情報を取得して認証を行う。

多要素認証 (MFA)

パスワードに加えて、SMSで送信されたコードや、認証アプリで生成されたコードなど、複数の認証要素を組み合わせて認証を行う方法です。セキュリティを強化するために有効です。

3. NextAuth.jsを使った認証の実装

NextAuth.jsは、Next.jsアプリケーションに認証機能を簡単に追加できるライブラリです。様々なプロバイダー(認証方法)をサポートしており、セッション管理やデータベースとの連携も簡単に行えます。

NextAuth.jsのインストール

まず、NextAuth.jsをインストールします。

bash
npm install next-auth
# または
yarn add next-auth
# または
pnpm add next-auth

環境変数の設定

NextAuth.jsを使用するには、いくつかの環境変数を設定する必要があります。.env.localファイルを作成し、以下のように設定します。

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your_secret_here
  • NEXTAUTH_URL: アプリケーションのURL
  • NEXTAUTH_SECRET: セッションの暗号化などに使用される秘密鍵(openssl rand -base64 32などで生成)

API Routeの作成

次に、NextAuth.jsのAPI Routeを作成します。pages/api/auth/[...nextauth].tsファイルを作成し、以下のコードを記述します。

typescript
// pages/api/auth/[...nextauth].ts

import NextAuth from 'next-auth';
import GithubProvider from 'next-auth/providers/github';

export const authOptions = {
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
    // 他のプロバイダーもここに追加できる
  ],
  // データベースの設定や、セッションの設定などもここに追加できる
};

export default NextAuth(authOptions);

この例では、GitHubを使った認証(OAuth)を設定しています。providers配列に、使用するプロバイダーを追加します。

GitHubプロバイダーを使用するには、GitHubでOAuthアプリケーションを作成し、Client IDClient Secretを取得する必要があります。取得した値を、.env.localファイルに追加します。

GITHUB_ID=your_github_client_id
GITHUB_SECRET=your_github_client_secret

認証状態の取得

useSessionフックを使うと、クライアントサイドで認証状態を取得できます。

tsx
// pages/index.tsx

import { useSession, signIn, signOut } from 'next-auth/react';

export default function Home() {
  const { data: session, status } = useSession();

  if (status === 'loading') {
    return <p>Loading...</p>;
  }

  if (session) {
    return (
      <div>
        <p>
          Signed in as {session.user?.email}
        </p>
        <button onClick={() => signOut()}>Sign out</button>
      </div>
    );
  }

  return (
    <div>
      <p>You are not signed in.</p>
      <button onClick={() => signIn('github')}>Sign in with GitHub</button>
    </div>
  );
}

useSessionフックは、dataプロパティにセッション情報、statusプロパティに認証状態(loadingauthenticatedunauthenticated)を返します。

signIn関数を使うと、指定したプロバイダーでサインイン処理を開始できます。signOut関数を使うと、サインアウト処理を実行できます。

サーバーサイドでの認証状態の取得

getServerSession関数を使うと、サーバーサイド(getServerSidePropsなど)で認証状態を取得できます。

tsx
// pages/protected.tsx

import { GetServerSidePropsContext } from 'next';
import { getServerSession } from 'next-auth/next';
import { authOptions } from './api/auth/[...nextauth]';

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const session = await getServerSession(context.req, context.res, authOptions);

  if (!session) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    };
  }

  return {
    props: {
      session,
    },
  };
}

export default function ProtectedPage({ session }: { session: any }) {
  return (
    <div>
      <h1>Protected Page</h1>
      <p>You are signed in as {session.user?.email}</p>
    </div>
  );
}

getServerSession関数に、リクエストオブジェクト、レスポンスオブジェクト、authOptionsを渡すことで、サーバーサイドでセッション情報を取得できます。

セッションが存在しない場合は、リダイレクトなどの処理を行います。