認証

認証(Authentication)はユーザーが誰であるかを確認し、認可(Authorization)はユーザーがアクセスできる内容を制御します。Next.jsはさまざまな認証パターンをサポートしており、それぞれ異なるユースケースに対応しています。このページでは各ケースについて説明し、制約条件に基づいて選択できるようにします。

認証パターン

適切な認証パターンを特定する最初のステップは、使用したいデータ取得戦略を理解することです。その後、この戦略をサポートする認証プロバイダーを決定できます。主に2つのパターンがあります:

静的生成ページの認証

Next.jsは、ブロッキングデータ要件がない場合、ページが静的であると自動的に判断します。これはページ内にgetServerSidePropsgetInitialPropsが存在しないことを意味します。代わりに、サーバーからローディング状態をレンダリングし、その後クライアントサイドでユーザーを取得できます。

このパターンの利点の1つは、ページをグローバルCDNから配信し、next/linkを使用してプリロードできることです。実際には、これによりTTI(Time to Interactiveが向上します。

プロフィールページの例を見てみましょう。最初にローディングスケルトンを表示し、ユーザーリクエストが完了するとユーザー名を表示します:

pages/profile.js
import useUser from '../lib/useUser'
import Layout from '../components/Layout'

const Profile = () => {
  // クライアントサイドでユーザーを取得
  const { user } = useUser({ redirectTo: '/login' })

  // サーバー側でローディング状態をレンダリング
  if (!user || user.isLoggedIn === false) {
    return <Layout>Loading...</Layout>
  }

  // ユーザーリクエスト完了後、ユーザーを表示
  return (
    <Layout>
      <h1>Your Profile</h1>
      <pre>{JSON.stringify(user, null, 2)}</pre>
    </Layout>
  )
}

export default Profile

この動作例を確認できます。with-iron-sessionの例で実際の動作を確認してください。

サーバーサイドレンダリングページの認証

ページからasync関数getServerSidePropsをエクスポートすると、Next.jsは各リクエスト時にgetServerSidePropsから返されたデータを使用してページをプリレンダリングします。

export async function getServerSideProps(context) {
  return {
    props: {}, // ページコンポーネントにpropsとして渡されます
  }
}

プロフィール例をサーバーサイドレンダリング(SSR)を使用するように変更してみましょう。セッションがある場合、ページ内のProfileコンポーネントにuserをpropsとして渡します。この例ではローディングスケルトンがありません。

pages/profile.js
import withSession from '../lib/session'
import Layout from '../components/Layout'

export const getServerSideProps = withSession(async function ({ req, res }) {
  const { user } = req.session

  if (!user) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    }
  }

  return {
    props: { user },
  }
})

const Profile = ({ user }) => {
  // ユーザーを表示。ローディング状態は不要
  return (
    <Layout>
      <h1>Your Profile</h1>
      <pre>{JSON.stringify(user, null, 2)}</pre>
    </Layout>
  )
}

export default Profile

このパターンの利点は、リダイレクト前に未認証コンテンツがちらつくのを防げることです。getServerSidePropsでユーザーデータを取得すると、認証プロバイダーへのリクエストが解決するまでレンダリングがブロックされることに注意してください。ボトルネックを作成しTTFB(Time to First Byteを増加させないためには、認証ルックアップを高速化する必要があります。そうでない場合は、静的生成を検討してください。

認証プロバイダー

認証パターンについて説明したので、特定のプロバイダーとNext.jsでの使用方法を見てみましょう。

独自データベースの使用

ユーザーデータを含む既存のデータベースがある場合、プロバイダーに依存しないオープンソースソリューションを利用すると良いでしょう。

  • 低レベルで暗号化されたステートレスなセッション機能が必要な場合はiron-sessionを使用
  • 組み込みプロバイダー(Google、Facebook、GitHubなど)、JWT、JWE、メール/パスワード、マジックリンクなど包括的な認証システムが必要な場合はnext-authを使用

これらのライブラリはどちらも認証パターンをサポートしています。Passportに興味がある場合は、安全で暗号化されたクッキーを使用した例もあります:

その他のプロバイダー

他の認証プロバイダーの例については、examplesフォルダを確認してください。