Next.js 13 以降で導入された App Router は、ページごとに page.tsx を配置するだけで自動的にルーティングが組み立てられます。
しかし、ログインが必要なページと誰でもアクセスできるページを同じプロジェクト内で管理すると、認証ロジックが散在しがちです。そこで ミドルウェア を使って「保護したいルートだけを一括で切り分ける」パターンを紹介します。
1. ミドルウェアの役割をざっくりイメージ
ミドルウェアはリクエストがページに到達する前に実行される関数です。
- 認証情報(Cookie やヘッダー)をチェック
- 条件に合わなければ別ページへリダイレクト
- 条件が合えばそのまま次の処理へ
この仕組みを利用すれば、/dashboard や /profile といった保護ルートだけをまとめてガードできます。
2. ディレクトリ構成の例
app/
├─ layout.tsx # ルートレイアウト
├─ page.tsx # トップページ(公開)
├─ login/
│ └─ page.tsx # ログインページ(公開)
└─ protected/
├─ layout.tsx # 保護レイアウト(ミドルウェアでチェック)
└─ page.tsx # 守られたページ
middleware.ts # グローバルミドルウェア
middleware.ts はプロジェクトのルートに置くだけで全リクエストに適用されます。
ポイントは、保護したいパスだけを正規表現で絞り込むことです。
3. 実装例(TypeScript)
以下はシンプルな認証ミドルウェアです。
-
authTokenという名前の Cookie が存在すれば認証成功とみなす - それ以外は
/loginへリダイレクト
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
// 保護したいパスを配列で管理
const protectedPaths = ['/protected', '/dashboard', '/profile'];
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 保護対象外ならそのまま通す
if (!protectedPaths.some(p => pathname.startsWith(p))) {
return NextResponse.next();
}
// Cookie からトークン取得
const token = request.cookies.get('authToken')?.value;
// トークンが無ければログインページへリダイレクト
if (!token) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('callbackUrl', pathname);
return NextResponse.redirect(loginUrl);
}
// 認証成功 → 次の処理へ
return NextResponse.next();
}
// ミドルウェアが適用されるパスを明示(オプション)
export const config = {
matcher: ['/protected/:path*', '/dashboard/:path*', '/profile/:path*'],
};
コードのポイント
-
protectedPathsでガードしたいルートを列挙。増減があればここだけ修正すれば OK。 -
request.cookies.getで Cookie を安全に取得。?.valueで未定義時もエラーにならないようにしています。 -
callbackUrlをクエリに入れてリダイレクトすれば、ログイン後に元のページへ戻すことができます。 -
config.matcherを設定すると、不要なリクエストまでミドルウェアが走らずパフォーマンスが向上します。
4. 初心者がハマりやすいポイント
| つまずきやすい点 | 対策 |
|---|---|
| Cookie 名を間違える | ブラウザの DevTools で実際に送られている名前を確認 |
| 正規表現でパスが抜ける |
matcher に /:path* を付けてサブパスも網羅 |
| リダイレクトが無限ループになる |
/login 自体は protectedPaths に入れない |
| TypeScript の型エラー |
NextRequest と NextResponse のインポートは必ず next/server から |
5. まとめ
- App Router でページ構造をシンプルに保ちつつ、ミドルウェアで認証ロジックを一元管理できる
- 保護したいルートだけを
matcherで絞ると、余計な処理が走らず高速化 - 初心者でも TypeScript の型補完があるので、実装ミスを減らしながら安全に認証フローを構築できる
実際に手を動かしてみると、ミドルウェアの挙動がすぐに分かります。ぜひ自分のプロジェクトに取り入れて、保護ルートの管理を楽にしてみてください。