🐲

[Next.js] middleware複雑化してない?NEMOを紹介する

2024/10/20に公開

この記事を読んでほしい人

Next.jsで開発をしていて、middlewareが肥大化してしまっている人にぜひ読んでほしいです。

NEMOとは?

NEMOの公式ドキュメント

Githubはこちら

実装してみる

何はともあれ実際のコードを見た方が理解が早いので、以下の2つを実装したコードを紹介します。

  • 全画面に対してベーシック認証をする
  • ログイン状態で/loginに遷移した場合、/にリダイレクトする

全画面に対してベーシック認証をする

middleware.ts
import { type MiddlewareFunctionProps, createMiddleware } from "@rescale/nemo"
import { NextResponse } from "next/server"

const basicAuthentication = async ({ request, response }: MiddlewareFunctionProps) => {
  const basicAuth = request.headers.get("authorization")
  if (basicAuth) {
    const [user, password] = atob(basicAuth.split(" ")[1]).split(":")
    if (user === process.env.BASIC_AUTH_USERNAMpE && password === process.env.BASIC_AUTH_PASSWORD) {
      return response // responseはNextResponse.next()と同じ型で同義です
    }
  }
  return new NextResponse("Basic Authentication Required.", { status: 401, headers: { "WWW-authenticate": 'Basic realm="Secure Area"' } })
}

export const middleware = createMiddleware({
  "*": [basicAuthentication], // 全画面適用なのでワイルドカード"*"を指定しています
})

ログイン状態で/loginに遷移した場合、/にリダイレクトする

middleware.ts
import { type MiddlewareFunctionProps, createMiddleware } from "@rescale/nemo"
import { NextResponse } from "next/server"

const basicAuthentication = async ({ request, response }: MiddlewareFunctionProps) => {
  const basicAuth = request.headers.get("authorization")
  if (basicAuth) {
    const [user, password] = atob(basicAuth.split(" ")[1]).split(":")
    if (user === process.env.BASIC_AUTH_USERNAMpE && password === process.env.BASIC_AUTH_PASSWORD) {
      return response
    }
  }
  return new NextResponse("Basic Authentication Required.", { status: 401, headers: { "WWW-authenticate": 'Basic realm="Secure Area"' } })
}

export const middleware = createMiddleware({
  "*": [basicAuthentication],
+  "/login": [
+    async ({ request }: MFProps) => {
+      const user = await userService.getMe() // ログインユーザーを取得します
+      if (!user) return NextResponse.next()
+      const url = request.nextUrl.clone()
+      url.pathname = "/"
+      return NextResponse.redirect(url)
+    },
+  ],
})

最後に

今回実装した部分だけだとあまり良さが伝わらないですが、ユーザー権限によって画面制御が必要なプロジェクトなどにおいては、かなり有用なのではと思います。

ぜひ試してみてください。

Discussion