2023.08.07[Mon]

NextAuth.jsを利用してユーザー権限毎に認証を実装する

  • React
  • Next.js

目次

  • - 環境
  • - NextAuth.jsとは
  • - 実装
  • - ユーザー権限をトークンに設定する
  • - middlewareに認証を実装する
  • - 終わりに

こんにちは、Webエンジニアの永井です。

今回はNextAuth.jsを利用してログインユーザーの権限毎に認証を実装する方法を紹介します。
サイトのページによっては特定の権限を持つユーザーのみアクセス可能にしたい場合があると思うので、その場合に役立ちます。

環境

next: 13.4.7
next-auth: 4.22.1

NextAuth.jsとは

NextAuth.jsは、Next.jsアプリケーションで簡単に認証機能を実装するためのフレームワークです。様々な認証プロバイダー(Google、Facebook、Twitterなど)と連携し、ユーザーのログインやセッション管理を行うことができます。

ユーザー権限毎に認証を実装するには、NextAuth.jsのmiddlewareの機能と、Next.jsのmiddlewareの機能を組み合わせて使う必要があります。なので、それぞれの特徴について簡単に見ておきます。

Next.js

Next.jsのmiddlewareを使うと、ページにアクセスする前に処理を実行することができます。リクエストの内容に応じた前処理や認証、リダイレクトなどに適しています。
実装はmiddleware.ts (or .js)をプロジェクトのルート直下src直下に配置して行います。

NextAuth.js

NextAuth.jsのmiddlewareでは、サイト全体に認証を付けたり、特定ページのみに認証を付けたりすることができます。
実装自体はNext.jsのmiddlewareファイルに書きます。

実装

例として、以下のようなサイトを想定して実装します。

  • ログインユーザーの権限は「管理者」「ユーザー」の二つ
  • ログインページ以外でログインが必要
  • 特定ページのみ「管理者」権限が必要
  • 特定ページに「管理者」以外がアクセスした場合は404を返す

ユーザー権限をトークンに設定する

まず、トークンに権限を設定します。このトークンをmiddlewareで受け取って権限の判定を行います。

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

import NextAuth, { NextAuthOptions } from "next-auth"

export const authOptions: NextAuthOptions = {
...
  callbacks: {
    async jwt({ token }) {
      token.userRole = getUserRole();
      return token;
    },
  },
};

export default NextAuth(authOptions);

このままではtoken.userRoleで型エラーが出てしまうので、型定義ファイルを作成して解決します。

import "next-auth/jwt"

declare module "next-auth/jwt" {
  interface JWT {
    userRole?: "admin" | "user";
  }
}

middlewareに認証を実装する

設定したトークンを元に権限を判定して、認証を実装します。

// src/middleware.ts

import { NextResponse } from 'next/server';
import { withAuth } from 'next-auth/middleware';

// 管理者権限が必要なパス一覧
const adminOnlyPathRegexs = [
  new RegExp(`^/xxx/.*$`),
  ...
];

export default withAuth(
  function middleware(req) {
    const { pathname } = req.nextUrl;

    // 管理者権限のないユーザーが管理者権限が必要なパスにアクセスした場合は404
    if (
      req.nextauth.token?.userRole !== "admin" &&
      adminOnlyPathRegexs.some((regex) => regex.test(pathname))
    ) {
      return NextResponse.rewrite(new URL('/404', req.url));
    }
  }
);

export const config = {
  // ログインページ(/login)以外を対象にする
  matcher: '/((?!login).*)',
};

これでユーザー権限毎に認証を実装できました。

今回は省略していますが、middleware関数が呼ばれる前にcallbacksの設定が呼ばれます。この中のauthorizedでは、falseを返すことでログインページにリダイレクトさせることが可能です。
デフォルトでは、ログイン済みの場合(tokenがある)にtrueが返され、未ログインではログインページにリダイレクトされます。

// Example (default value)

export default withAuth(
...
 callbacks: {
   authorized({ req , token }) {
     if(token) return true; // If there is a token, the user is authenticated
   }
 }
};

例えば、管理者以外はログインページにリダイレクトしたい場合はこちらで判定することができます。

export default withAuth(
...
 callbacks: {
   authorized({ req , token }) {
     return token?.userRole === "admin";
   }
 }
};

終わりに

NextAuth.jsを利用して認証を実装する方法を紹介しました。
NextAuth.jsを使うと簡単に実装できるのでぜひ活用してください。

Share

Shopify注文確認メールのカスタマイズ方法Shopifyの多言語対応における豆知識。複数の翻訳アプリが共存できる