【Next.js】unauthorized.jsxとforbidden.jsx使ってみた
リテールアプリ共創部のるおんです。
Next.jsのバージョン15から、認証・認可に関する新しい機能としてunauthorized.jsx
とforbidden.jsx
が実験的に導入されました。これらの機能を使用することで、より簡単にアプリケーションの認証・認可の制御を行うことができます。
今回はこれらの機能について調べてみたので共有したいと思います。
unauthorized.jsxとforbidden.jsxとは
これらは、Next.jsが提供する認証・認可のエラーハンドリングのための機能です。
Next.jsでは、notFound
関数を呼び出すことでnot-found.tsx
を表示させることができますが、これと同じように以下のファイルと関数がサポートされました。
- unauthorized.tsx:
unauthorized
関数により呼び出される401エラー(未認証)時の表示コンポーネント - forbidden.tsx:
forbidden
関数により呼び出される403エラー(権限なし)時の表示コンポーネント
これらのファイルを用意することで、アプリケーション全体で統一された認証・認可のエラーハンドリングを実現することができます。
先にこれらの使い方を知りたい方は、使ってみるをまずご覧ください。
これらの関数は以下の場所で使用することができます:
- Server Components
- Server Actions
- Route Handlers
いわゆるReactのサーバー側の処理をかける部分ですね。ただし、root layoutでは使用できません。
内部的には、これらの関数でErrorを発生させて、Errorのstatusコードに応じて表示させるコンポーネントを切り替えているようです。
- 401エラー:unauthorized.tsx
- 403エラー:forbidden.tsx
- 404エラー:not-found.tsx
コンポーネントの階層は以下のようになるようです。
<Layout>
<Template>
<ErrorBoundary fallback={<Error />}>
<Suspense fallback={<Loading />}>
- <ErrorBoundary fallback={<NotFound />}>
+ <ErrorBoundary fallback={<NotFound /> または <Unauthorized /> または <Forbidden />}
<Page />
</ErrorBoundary>
</Suspense>
</ErrorBoundary>
</Template>
</Layout>
使ってみる
セットアップ
これらの機能を使用するには、2024/12/11時点でnext.config.js
で実験的機能を有効にする必要があります。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
+ authInterrupts: true,
},
}
export default nextConfig
unauthorized.jsx
unauthorized
関数を用いると、ログインしていないユーザーに対して自動でunauthorized.jsx
を表示させることができます。
以下のように、unauthorized.jsx
を作成しました。
src
└─ app
├─ page.jsx
+ ├─ unauthorized.jsx
└─ lib
└─ auth.js
export default function Unauthorized() {
return (
<div>
<div>
<h1>ログインしてください</h1>
<form>
<div>
<label>メールアドレス</label>
<input />
</div>
<div>
<label>パスワード</label>
<input />
</div>
<button>ログイン</button>
</form>
</div>
</div>
);
}
getServerSession
というユーザーのログイン情報を取得する関数があるとします。page.tsx
において、この関数を呼び出してログイン情報がない場合、unauthorized
関数を呼び出すようにします。
import { getServerSession } from "./lib/auth";
import { unauthorized } from "next/navigation";
export default async function Page() {
const session = await getServerSession();
+ if (!session) {
+ unauthorized();
+ }
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<div>
<h1>Hello World</h1>
</div>
</div>
);
}
すると、以下の画像のように実際に未認証画面(unauthorized.tsx
)を表示させることができます。
forbidden.jsx
次に、認証はできているが特定の権限(例:管理者権限)が必要なページでは、forbidden()
関数を使用して権限無し画面(forbidden.jsx
)を表示させることができます。
adminセグメントを作成し、forbidden.jsx
を作成します。
src
└─ app
+ ├─ admin
+ │ ├─ forbidden.jsx
+ │ ├─ page.jsx
└─ lib
└─ auth.js
export default function Forbidden() {
return (
<div className="flex h-screen items-center justify-center">
<div className="rounded-lg bg-white p-8 shadow-lg">
<h1 className="mb-4 text-2xl font-bold text-gray-800">Forbidden</h1>
<p className="text-gray-600">権限がありません</p>
</div>
</div>
);
}
例えば、page.jsxにおいてユーザーの権限がadmin権限じゃない場合、forbidden
関数を呼び出します。
import { forbidden, unauthorized } from "next/navigation";
import { getServerSession } from "../lib/auth";
export default async function Page() {
const session = await getServerSession();
+ if (session.user.role == 'admin') {
+ forbidden();
+ }
return (
<main>
<h1>Welcome to the Admin Page</h1>
<p>Hi, {session.user.name}.</p>
</main>
);
}
forbidden
関数が実行されると、以下のようにforbidden.jsx
で定義したカスタムページが表示されます
これまでと何が変わったか
これまでは、これらのユーザーの存在有無とロールなどの特定の属性に応じたリダイレクト先を自前で実装してあげる必要がありました。
これまで
これまでは、ログインしていない場合の画面や、権限がない場合の画面を専用で表示させるためには、それぞれディレクトを作成してセグメントを用意し、直接リダイレクトさせる必要がありました。
今回のアップデートで、リダイレクトさせずともURLのパスを変更しないまま描画するコンポーネントを変えられるようになったということです。
import { forbidden, redirect, unauthorized } from "next/navigation";
import { getServerSession } from "../lib/auth";
export default async function Page() {
const session = await getServerSession();
if (!session) {
- redirect("/login"); // これまでは、https://url/loginにリダイレクト
+ unauthorized();
}
if (session.user.role !== "admin") {
- redirect("/forbidden"); // これまでは。https://url/forbiddenにリダイレクト
+ forbidden();
}
return (
<main>
<h1>Welcome to the Admin Dashboard</h1>
<p>Hi, {session.user.role}.</p>
</main>
);
}
src
└─ app
├─ admin
+ │ ├─ forbidden.tsx
│ └─ page.tsx
- ├─ forbidden // 各ルートを作成してあげる必要があった
- │ └─ page.tsx
- ├─ login
- │ └─ page.tsx
├─ lib
│ └─ auth.ts
├─ layout.tsx
├─ page.tsx
+ └─ unauthorized.tsx
これまでと変わらないところ
pageごとに認証チェックと権限チェックを行わないところは今までと変わりません。そのため、各セグメントのpage.tsxや各Server Actionなどにはこれまで通り毎回チェック処理と関数の呼び出しを書く必要があります。
毎回これらの関数を呼び出す書く必要があるのでそこまでコード量などに大きな変化は見られそうにないです。
おわりに
Next.jsのunauthorized.jsx
とforbidden.jsx
を使用することで、アプリケーションの認証・認可の制御がより簡単になりました。
ただし、現時点では実験的な機能であるため、今後の正式リリースが待ちたいと思います。
以上。どなたかの参考になれば幸いです。
参考